diff --git a/docs/dev.md b/docs/dev.md index a15515e63..045eea7c8 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -6,7 +6,8 @@ Start a Liberty instance in dev mode. This goal also invokes the `create`, `inst Starting in version 3.6.1, dev mode invokes the `generate-features` goal when the `generateFeatures` configuration parameter is set to `true`. **This goal modifies the source configuration directory of your application.** See [generate-features](generate-features.md) for details. The default value for the `generateFeatures` parameter is `false`. When auto-generation of features is turned on, dev mode has a runtime dependency on IBM WebSphere Application Server Migration Toolkit for Application Binaries, which is separately licensed under IBM License Agreement for Non-Warranted Programs. For more information, see the [license](https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/wamt). -Additionally, starting in 3.5.2-SNAPSHOT, [resource variable filtering](https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html) and [WAR overlays](https://maven.apache.org/plugins/maven-war-plugin/overlays.html) are supported for loose WAR applications. This is done by automatically detecting appropriate Maven WAR plugin configuration and calling the WAR plugin's `exploded` goal and the Maven Resource plugin's `resource` goal when appropriate. Behavior for updating/deleting resources is delegated via the Maven WAR plugin configuration, including the `outdatedCheckPath` parameter enhanced in plugin version 3.3.2. +Additionally, starting in version 3.5.2, [resource variable filtering](https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html) and [WAR overlays](https://maven.apache.org/plugins/maven-war-plugin/overlays.html) are supported for loose WAR applications. This is done by automatically detecting appropriate Maven WAR plugin configuration and calling the WAR plugin's [`exploded`](https://maven.apache.org/plugins/maven-war-plugin/exploded-mojo.html) goal and the Maven Resource plugin's [`resource`](https://maven.apache.org/plugins/maven-resources-plugin/resources-mojo.html) goal when appropriate. Behavior for updating/deleting resources can be configured via the [`outdatedCheckPath`](https://maven.apache.org/plugins/maven-war-plugin/exploded-mojo.html#outdatedCheckPath) parameter introduced and then enhanced in maven-war-plugin versions 3.3.1, 3.3.2. + To start the server in a container, see the [devc](#devc-container-mode) section below. diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/META-INF/MANIFEST.MF b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/META-INF/MANIFEST.MF new file mode 100644 index 000000000..8836a83e2 --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Created-By: 17.0.3 (IBM Corporation) + diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/invoker.properties b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/invoker.properties new file mode 100644 index 000000000..baf93bcbf --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/invoker.properties @@ -0,0 +1,4 @@ +invoker.goals.1 = -Poverlay clean compile liberty:create liberty:install-feature liberty:deploy verify +invoker.goals.2 = -Pnon-exploded clean compile liberty:create liberty:install-feature liberty:deploy verify +invoker.goals.3 = -Pfiltered-web-resource clean compile liberty:create liberty:install-feature liberty:deploy verify +invoker.goals.4 = -Pfiltered-dd clean compile liberty:create liberty:install-feature liberty:deploy verify diff --git a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/pom.xml b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/pom.xml old mode 100755 new mode 100644 similarity index 51% rename from liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/pom.xml rename to liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/pom.xml index 4654d6c19..8db7438b8 --- a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/pom.xml +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/pom.xml @@ -1,13 +1,16 @@ - + - 4.0.0 - dev-it-tests - exploded-war-proj - 1.0-SNAPSHOT + + io.openliberty.tools.it + tests + 1.0-SNAPSHOT + + + deploy-loose-config-exploded-it war @@ -15,58 +18,14 @@ UTF-8 1.7 1.7 - LibertyProject - - 9080 - 9443 - - usr - - - - - io.openliberty.features - features-bom - RUNTIME_VERSION - pom - import - - - - - - - io.openliberty.features - jaxrs-2.1 - esa - provided - - - io.openliberty.features - jsonp-1.1 - esa - provided - - - io.openliberty.features - cdi-2.0 - esa - provided - - - io.openliberty.features - mpConfig-1.3 - esa - provided - - - io.openliberty.features - mpRestClient-1.2 - esa - provided - + + javax.servlet + javax.servlet-api + 3.1.0 + provided + junit @@ -131,21 +90,22 @@ 1.2.3 runtime - - - + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + **/*.java + + + org.apache.maven.plugins maven-war-plugin @@ -153,65 +113,27 @@ false pom.xml - - - - + + + + ${project.basedir}/src/main/resource1 + false + + false - - - org.apache.maven.plugins - maven-surefire-plugin - 3.1.2 - - - test - default-test - - - **/it/** - - ${project.build.directory}/test-reports/unit - - - - + io.openliberty.tools liberty-maven-plugin - SUB_VERSION + @pom.version@ - - io.openliberty - openliberty-kernel - RUNTIME_VERSION - zip - - ${app.name} - ${packaging.type} - - ${testServerHttpPort} - ${testServerHttpsPort} - json - - + true - + org.apache.maven.plugins maven-failsafe-plugin @@ -223,16 +145,6 @@ integration-test - - - **/it/**/*.java - - - - ${testServerHttpPort} - - - verify-results @@ -242,10 +154,121 @@ - ${project.build.directory}/test-reports/it/failsafe-summary.xml + + ${project.build.directory}/test-reports/it/failsafe-summary.xml ${project.build.directory}/test-reports/it + + + non-exploded + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/NonExplodedTest.java + + + **/ExplodedTest.java + + + + + + + + + overlay + + + + org.apache.maven.plugins + maven-war-plugin + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/ExplodedTest.java + + + **/ExplodedFilteredDDTest.java + **/NonExplodedTest.java + + + + + + + + filtered-web-resource + + + + org.apache.maven.plugins + maven-war-plugin + + + + ${project.basedir}/src/main/resource2 + true + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/ExplodedTest.java + + + **/ExplodedFilteredDDTest.java + **/NonExplodedTest.java + + + + + + + + filtered-dd + + + + org.apache.maven.plugins + maven-war-plugin + +true + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/ExplodedFilteredDDTest.java + + + **/ExplodedTest.java + **/NonExplodedTest.java + + + + + + + diff --git a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloServlet.java b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/java/mypkg/HelloServlet.java similarity index 71% rename from liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloServlet.java rename to liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/java/mypkg/HelloServlet.java index 01cc44f09..7bb82878b 100644 --- a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloServlet.java +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/java/mypkg/HelloServlet.java @@ -1,5 +1,5 @@ /******************************************************************************* - * (c) Copyright IBM Corporation 2021. + * (c) Copyright IBM Corporation 2019. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -package com.demo; +package mypkg; import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; @@ -30,10 +27,18 @@ public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; - private static final Logger log = LoggerFactory.getLogger(HelloLogger.class); - + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) + */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - log.info("SLF4J Logger is ready for messages."); - response.getWriter().append("hello world"); + String msg = "greeting"; + response.getWriter().append(msg); + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + doGet(request, response); } -} \ No newline at end of file +} diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/liberty/config/server.xml b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/liberty/config/server.xml new file mode 100644 index 000000000..6050da10a --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/liberty/config/server.xml @@ -0,0 +1,22 @@ + + + + jsp-2.3 + + + + diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/resource1/keepalive.txt b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/resource1/keepalive.txt new file mode 100644 index 000000000..f7d55cf9a --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/resource1/keepalive.txt @@ -0,0 +1 @@ +r1 diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/resource2/keepalive.txt b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/resource2/keepalive.txt new file mode 100644 index 000000000..9a6c8d12d --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/resource2/keepalive.txt @@ -0,0 +1 @@ +r2 diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/webapp/WEB-INF/web.xml b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..baddd26c0 --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + Hello Servlet + + + index.html + + diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/webapp/index.html b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/webapp/index.html new file mode 100644 index 000000000..06dbf4635 Binary files /dev/null and b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/main/webapp/index.html differ diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/ExplodedFilteredDDTest.java b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/ExplodedFilteredDDTest.java new file mode 100644 index 000000000..43aeabd0b --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/ExplodedFilteredDDTest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * (c) Copyright IBM Corporation 2023. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package mypkg; + +import static mypkg.utils.LooseConfigUtils.*; + +import java.io.File; +import java.io.FileInputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.junit.Assert; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Web application test case + */ +public class ExplodedFilteredDDTest { + + @Test + public void testExplodedLooseAppFormat() throws Exception { + File in = new File("target/liberty/wlp/usr/servers/defaultServer/dropins/deploy-loose-config-exploded-it.war.xml"); + FileInputStream input = new FileInputStream(in); + + // get input XML Document + DocumentBuilderFactory inputBuilderFactory = DocumentBuilderFactory.newInstance(); + inputBuilderFactory.setIgnoringComments(true); + inputBuilderFactory.setCoalescing(true); + inputBuilderFactory.setIgnoringElementContentWhitespace(true); + inputBuilderFactory.setValidating(false); + DocumentBuilder inputBuilder = inputBuilderFactory.newDocumentBuilder(); + Document inputDoc=inputBuilder.parse(input); + + // parse input XML Document + XPath xPath = XPathFactory.newInstance().newXPath(); + + String expression = "/archive//*"; + NodeList nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of archive elements ==>", 4, nodes.getLength()); + + expression = "/archive/dir"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 3, nodes.getLength()); + + // 1. validate: + // + validateSrcResourceRoot(nodes.item(0), "src" + File.separator + "main" + File.separator + "resource1"); + + // 2. validate: + // + validateTargetClasses(nodes.item(1)); + + // 3. validate: + // + validateWebAppDirRoot(nodes.item(2), "deploy-loose-config-exploded-it-1.0-SNAPSHOT"); + } +} diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/ExplodedTest.java b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/ExplodedTest.java new file mode 100644 index 000000000..5fa493ad1 --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/ExplodedTest.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * (c) Copyright IBM Corporation 2023. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package mypkg; + +import static mypkg.utils.LooseConfigUtils.*; + +import java.io.File; +import java.io.FileInputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.junit.Assert; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +/** + * Web application test case + */ +public class ExplodedTest { + + @Test + public void testExplodedLooseAppFormat() throws Exception { + File in = new File("target/liberty/wlp/usr/servers/defaultServer/dropins/deploy-loose-config-exploded-it.war.xml"); + FileInputStream input = new FileInputStream(in); + + // get input XML Document + DocumentBuilderFactory inputBuilderFactory = DocumentBuilderFactory.newInstance(); + inputBuilderFactory.setIgnoringComments(true); + inputBuilderFactory.setCoalescing(true); + inputBuilderFactory.setIgnoringElementContentWhitespace(true); + inputBuilderFactory.setValidating(false); + DocumentBuilder inputBuilder = inputBuilderFactory.newDocumentBuilder(); + Document inputDoc=inputBuilder.parse(input); + + // parse input XML Document + XPath xPath = XPathFactory.newInstance().newXPath(); + + String expression = "/archive//*"; + NodeList nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of archive elements ==>", 5, nodes.getLength()); + + expression = "/archive/dir"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 4, nodes.getLength()); + + // 1. validate: + // + validateSrcMainWebAppRoot(nodes.item(0)); + + // 2. validate: + // + validateSrcResourceRoot(nodes.item(1), "src" + File.separator + "main" + File.separator + "resource1"); + + // 3. validate: + // + validateTargetClasses(nodes.item(2)); + + // 4. validate: + // + validateWebAppDirRoot(nodes.item(3), "deploy-loose-config-exploded-it-1.0-SNAPSHOT"); + } + +} diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/NonExplodedTest.java b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/NonExplodedTest.java new file mode 100644 index 000000000..867a9671e --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/NonExplodedTest.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * (c) Copyright IBM Corporation 2023. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package mypkg; + +import static mypkg.utils.LooseConfigUtils.validateSrcMainWebAppRoot; +import static mypkg.utils.LooseConfigUtils.validateTargetClasses; + +import java.io.File; +import java.io.FileInputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; + +import org.junit.Assert; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Web application test case + */ +public class NonExplodedTest { + + @Test + public void testNonExplodedLooseAppFormat() throws Exception { + File in = new File("target/liberty/wlp/usr/servers/defaultServer/dropins/deploy-loose-config-exploded-it.war.xml"); + FileInputStream input = new FileInputStream(in); + + // get input XML Document + DocumentBuilderFactory inputBuilderFactory = DocumentBuilderFactory.newInstance(); + inputBuilderFactory.setIgnoringComments(true); + inputBuilderFactory.setCoalescing(true); + inputBuilderFactory.setIgnoringElementContentWhitespace(true); + inputBuilderFactory.setValidating(false); + DocumentBuilder inputBuilder = inputBuilderFactory.newDocumentBuilder(); + Document inputDoc=inputBuilder.parse(input); + + // parse input XML Document + XPath xPath = XPathFactory.newInstance().newXPath(); + + String expression = "/archive//*"; + NodeList nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of archive elements ==>", 13, nodes.getLength()); + + expression = "/archive/dir"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 3, nodes.getLength()); + + // validate: + // + validateSrcMainWebAppRoot(nodes.item(0)); + + // validate: + // + validateTargetClasses(nodes.item(1)); + + expression = "/archive/file"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + + // validate: + // + String commonsLangBaseName = "commons-lang3-3.0.jar"; + boolean foundCommonsLangJar = false; + for (int i = 0; i < nodes.getLength() && !foundCommonsLangJar; i++) { + Node node = nodes.item(i); + String srcVal = node.getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + String targetVal = node.getAttributes().getNamedItem("targetInArchive").getNodeValue(); + if (srcVal.endsWith(commonsLangBaseName) && targetVal.endsWith(commonsLangBaseName)) { + foundCommonsLangJar = true; + } + } + Assert.assertTrue("Didn't find commons lang JAR in loose app XML ending with: " + commonsLangBaseName, foundCommonsLangJar); + } + +} diff --git a/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/utils/LooseConfigUtils.java b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/utils/LooseConfigUtils.java new file mode 100644 index 000000000..8efc190cd --- /dev/null +++ b/liberty-maven-plugin/src/it/deploy-loose-config-exploded-it/src/test/java/mypkg/utils/LooseConfigUtils.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * (c) Copyright IBM Corporation 2023. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package mypkg.utils; + +import java.io.File; + +import org.junit.Assert; +import org.w3c.dom.Node; + +public class LooseConfigUtils { + + public static void validateSrcMainWebAppRoot(Node archiveElem) { + // validate: + // + String s1 = archiveElem.getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + Assert.assertTrue("Bad node: " + s1, s1.endsWith("src" + File.separator + "main" + File.separator + "webapp")); + String t1 = archiveElem.getAttributes().getNamedItem("targetInArchive").getNodeValue(); + Assert.assertEquals("Bad node: " + t1, "/", t1); + } + + public static void validateSrcResourceRoot(Node archiveElem, String resourcePath) { + + // validate: + // + String s1 = archiveElem.getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + Assert.assertTrue("Bad node: " + s1, s1.endsWith(resourcePath)); + String t1 = archiveElem.getAttributes().getNamedItem("targetInArchive").getNodeValue(); + Assert.assertEquals("Bad node: " + t1, "/", t1); + } + + public static void validateWebAppDirRoot(Node archiveElem, String webAppName) { + + // validate: + // + String s1 = archiveElem.getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + Assert.assertTrue("Bad node: " + s1, s1.endsWith(webAppName)); + String t1 = archiveElem.getAttributes().getNamedItem("targetInArchive").getNodeValue(); + Assert.assertEquals("Bad node: " + t1, "/", t1); + } + + // validate: + // + public static void validateTargetClasses(Node archiveElem) { + String s1 = archiveElem.getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + Assert.assertTrue("Bad node: " + s1, s1.endsWith("target" + File.separator + "classes")); + String t1 = archiveElem.getAttributes().getNamedItem("targetInArchive").getNodeValue(); + Assert.assertEquals("Bad node: " + t1, "/WEB-INF/classes", t1); + } +} diff --git a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloLogger.java b/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloLogger.java deleted file mode 100755 index d717d81a5..000000000 --- a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloLogger.java +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - * (c) Copyright IBM Corporation 2021. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package com.demo; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; - -import static javax.ws.rs.core.MediaType.TEXT_PLAIN; - -@Path("/show-log") -public class HelloLogger { - private static final Logger log = LoggerFactory.getLogger(HelloLogger.class); - - @GET - @Produces(TEXT_PLAIN) - public String showLog() { - log.info("Here is the Log"); - return "Log has been shown"; - } -} diff --git a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloWorld.java b/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloWorld.java deleted file mode 100755 index 937240b5c..000000000 --- a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/java/com/demo/HelloWorld.java +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * (c) Copyright IBM Corporation 2021. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package com.demo; - -public class HelloWorld { - - public String helloWorld() { - return "helloWorld"; - } -} diff --git a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/liberty/config/server.xml b/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/liberty/config/server.xml deleted file mode 100755 index fdad620d8..000000000 --- a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/liberty/config/server.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - jaxrs-2.1 - - - - diff --git a/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/resources/placeHolder.txt b/liberty-maven-plugin/src/it/dev-it/resources/exploded-war-project/src/main/resources/placeHolder.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/liberty-maven-plugin/src/it/dev-it/src/test/java/net/wasdev/wlp/test/dev/it/ExplodedLooseWarAppTest.java b/liberty-maven-plugin/src/it/dev-it/src/test/java/net/wasdev/wlp/test/dev/it/ExplodedLooseWarAppTest.java deleted file mode 100644 index dbe139af8..000000000 --- a/liberty-maven-plugin/src/it/dev-it/src/test/java/net/wasdev/wlp/test/dev/it/ExplodedLooseWarAppTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/******************************************************************************* - * (c) Copyright IBM Corporation 2021. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *******************************************************************************/ -package net.wasdev.wlp.test.dev.it; - -import static org.junit.Assert.*; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.nio.file.Files; -import java.util.Scanner; - -import org.apache.commons.io.FileUtils; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -public class ExplodedLooseWarAppTest extends BaseDevTest { - private final String projectArtifact = "exploded-war-proj-1.0-SNAPSHOT"; - private final String appsDir = "target/liberty/wlp/usr/servers/defaultServer/dropins/"; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - setUpBeforeClass(null, "../resources/exploded-war-project"); - } - - @AfterClass - public static void cleanUpAfterClass() throws Exception { - BaseDevTest.cleanUpAfterClass(); - } - - @Ignore // TODO enable this test - @Test - public void configureWebXmlFiltering() throws Exception { - int appDeployedCount = countOccurrences("Running liberty:deploy", logFile); - // Add deployment descriptor filtering config to pom war plugin - replaceString("false", - "true", pom); - - // Verify exploded goal running and redeploy - assertTrue(getLogTail(), verifyLogMessageExists("Running liberty:deploy", 4000, logFile, ++appDeployedCount)); - assertTrue(getLogTail(), verifyLogMessageExists("Running maven-war-plugin:exploded", 2000)); - - // Verify loose app xml is correct - verifyExplodedLooseApp(); - - // Remove filtering config - replaceString("true", - "false", pom); - - // Verify redeploy - assertTrue(getLogTail(), verifyLogMessageExists("Running liberty:deploy", 2000)); - - // Verify loose app xml is back to how it was - verifyNonExplodedLooseApp(); - } - - @Ignore // TODO enable this test - @Test - public void configureFilteredResource() throws Exception { - // Add filtering config to pom war plugin (directory) - replaceString("", pom); - - replaceString("Filtered directory end -->", - "", pom); - - // Verify exploded goal running and redeploy - assertTrue(getLogTail(), verifyLogMessageExists("Running liberty:deploy", 2000)); - assertTrue(getLogTail(), verifyLogMessageExists("Running maven-war-plugin:exploded", 2000)); - - // Verify loose app xml is correct - verifyExplodedLooseApp(); - - // Remove filtering config - replaceString("", - "", - "Filtered directory end -->", pom); - - // Verify redeploy - assertTrue(getLogTail(), verifyLogMessageExists("Running liberty:deploy", 2000)); - - // Verify loose app xml is back to how it was - verifyNonExplodedLooseApp(); - } - - @Ignore // TODO enable this test - @Test - public void configureWarOverlay() throws Exception { - // Add filtering config to pom war plugin (directory) - replaceString("", pom); - - replaceString("Overlay configuration end -->", - "", pom); - - // Verify exploded goal running and redeploy - assertTrue(getLogTail(), verifyLogMessageExists("Running liberty:deploy", 2000)); - assertTrue(getLogTail(), verifyLogMessageExists("Running maven-war-plugin:exploded", 2000)); - - // Verify loose app xml is correct - verifyExplodedLooseApp(); - - // Remove filtering config - replaceString("", - "", - "Overlay configuration end -->", pom); - - // Verify redeploy - assertTrue(getLogTail(), verifyLogMessageExists("Running liberty:deploy", 2000)); - - // Verify loose app xml is back to how it was - verifyNonExplodedLooseApp(); - } - - private void verifyExplodedLooseApp() throws Exception { - String looseAppXml = tempProj.getAbsolutePath() + "/" + appsDir + projectArtifact + ".war.xml"; - - // Verify the target/ entry - String explodedWar = basicDevProj.getAbsolutePath() + "/target/" + projectArtifact; - assertTrue(getLogTail(), verifyFileExists(new File(looseAppXml), 3000)); - assertTrue(getLogTail(), verifyLogMessageExists("", 3000, new File(looseAppXml))); - } - - private void verifyNonExplodedLooseApp() throws Exception { - String looseAppXml = tempProj.getAbsolutePath() + "/" + appsDir + projectArtifact + ".war.xml"; - - // Verify the src/main/webapp entry - String srcMain = basicDevProj.getAbsolutePath() + "/src/main/webapp"; - assertTrue(getLogTail(), verifyLogMessageExists("", 3000, new File(looseAppXml))); - - // Verify the target/classes entry - String targetClasses = basicDevProj.getAbsolutePath() + "/target/classes"; - assertTrue(getLogTail(), verifyLogMessageExists("", 3000, new File(looseAppXml))); - } -} diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/DeployMojoSupport.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/DeployMojoSupport.java index b8a0b4bc0..e1df929ed 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/DeployMojoSupport.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/DeployMojoSupport.java @@ -146,27 +146,42 @@ protected void installLooseConfigWar(MavenProject proj, LooseConfigData config, // Validate maven-war-plugin version Plugin warPlugin = getPlugin("org.apache.maven.plugins", "maven-war-plugin"); - if (!validatePluginVersion(warPlugin.getVersion(), "3.3.1")) { - getLog().warn("Exploded WAR functionality is enabled. Please use maven-war-plugin version 3.3.1 or greater for best results."); + if (!validatePluginVersion(warPlugin.getVersion(), "3.3.2")) { + getLog().warn( + "Exploded WAR functionality is enabled. Please use maven-war-plugin version 3.3.2 or greater for best results."); } - // If I'm filtering web.xml, etc., I want to monitor from the exploded dir, not via a source dir - if (!looseWar.isFilteringDeploymentDescriptors()) { - looseWar.addSourceDir(); - } - - // Add source paths for non-filtered web resources. - // We'll already have the runtime application monitor watching for file changes, and we - // don't want to set up the more expensive dev mode type of watching. - looseWar.addNonFilteredWebResourcesConfigurationPaths(); - // Don't especially need to run it exactly here, but in debugger we can see what we have runExplodedMojo(); + //////////////////////////////////// + // The order matters and establishes a well-defined precedence as documented: https://www.ibm.com/docs/en/was-liberty/base?topic=liberty-loose-applications + // + // ".. If you have two files with the same target location in the loose archive, the first occurrence of the file is used. + // The first occurrence is based on a top-down approach to reading the elements of the loose application configuration file..." + // + // Because the flow is so complicated we may have cases where we are applying filtering where one location contains a filtered + // version of a file and another potentially has an unfiltered one, and in such cases we need to make sure the filtered version takes + // precedence. + // + // In certain cases, like step 1. below we avoid writing a location into the loose app XML because we don't want an unfiltered + // to take precedence and prevent the filtered value from taking effect. + // + //////////////////////////////////// + + // 1. Add source paths for the source dir and non-filtered web resources. Since there could be overlap, i.e. the source dir + // could also be configured as a web resource, we combine these into a single step. + // + // We'll already have the runtime application monitor watching for file changes, and we don't want to set up the more expensive + // dev mode type of watching. + looseWar.addNonFilteredSourceAndWebResourcesPaths(); + + // 2. target classes - this allows non-deploy mode cases (e.g. non-deploy cases such as `mvn compile` or m2e update in Eclipse) + // to pick up Java class updates upon compilation. + looseWar.addOutputDir(looseWar.getDocumentRoot(), new File(proj.getBuild().getOutputDirectory()), "/WEB-INF/classes"); + ////////////////////////// - // Per doc: https://www.ibm.com/docs/en/was-liberty/base?topic=liberty-loose-applications - // ".. If you have two files with the same target location in the loose archive, the first occurrence of the file is used. - // The first occurrence is based on a top-down approach to reading the elements of the loose application configuration file..." + // 3. Finally add the exploded dir // // In order to dynamically reflect changes in non-filtered web app source, this needs to go AFTER the unfiltered source entries above, since // changes in these un-monitored directories will NOT cause a new 'exploded' goal execution, so the updated content in the unmonitored source will @@ -181,14 +196,20 @@ protected void installLooseConfigWar(MavenProject proj, LooseConfigData config, } else { + // 1. looseWar.addSourceDir(); + // 2. looseWar.addOutputDir(looseWar.getDocumentRoot(), new File(proj.getBuild().getOutputDirectory()), "/WEB-INF/classes"); - // retrieve the directories defined as resources in the maven war plugin + // 3. retrieve the directories defined as resources in the maven war plugin + // + // TODO - It would be cleaner to avoid duplicating the source dir in the case it also appears as a web resource, like we do in the exploded case. + // If this ever became an issue we could combine this with step 1. above. However at the moment it doesn't seem worth the risk of making a change + // in such a key area. looseWar.addAllWebResourcesConfigurationPaths(); - // retrieves dependent library jar files + // 4. retrieves dependent library jar files addEmbeddedLib(looseWar.getDocumentRoot(), proj, looseWar, "/WEB-INF/lib/"); } diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/LooseWarApplication.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/LooseWarApplication.java index a4b9a95f3..910d1a4c4 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/LooseWarApplication.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/applications/LooseWarApplication.java @@ -36,42 +36,34 @@ public class LooseWarApplication extends LooseApplication { protected final MavenProject project; + + protected final Path warSourceDirectory; protected final Log log; public LooseWarApplication(MavenProject project, LooseConfigData config, Log log) { super(project.getBuild().getDirectory(), config); this.project = project; + this.warSourceDirectory = getWarSourceDirectory(project); this.log = log; } public static boolean isExploded(MavenProject project) { - boolean isExplodedWar = false; - - // Check if filtering is enabled - List dynamicWebResources = getFilteredWebSourceDirectories(project); - - if (!dynamicWebResources.isEmpty() || isUsingOverlays(project)) { - isExplodedWar = true; - } - - // TODO: Check additional filtering options (properties?) - - return isExplodedWar; + if (isUsingOverlays(project)) { + return true; + } else if (!getWebSourceDirectoriesToMonitor(project).isEmpty()) { + return true; + } else { + return false; + } } - public boolean isExploded() { return isExploded(project); } public void addSourceDir() throws IOException { - Path warSourceDir = getWarSourceDirectory(); - config.addDir(warSourceDir.toFile(), "/"); - } - - public Path getWarSourceDirectory() { - return getWarSourceDirectory(project); + config.addDir(warSourceDirectory.toFile(), "/"); } private static Path getWarSourceDirectory(MavenProject project) { @@ -102,10 +94,36 @@ private Path getWebAppDirectory(MavenProject project) { } } - public static List getFilteredWebSourceDirectories(MavenProject project) { + /** + * @param project + * + * @return A list of directory Path(s) including each web source directory that has filtering applied, including the war source + * directory (if so configured) or webResources entries + */ + public static List getWebSourceDirectoriesToMonitor(MavenProject project) { + + Set filteredWebResources = getFilteredWebResourcesConfigurations(project); - List retVal = new ArrayList(); + List retVal = new ArrayList(filteredWebResources); + Path warSourceDir = getWarSourceDirectory(project); + + // Need to add warSourceDir if DD filtering enabled, unless it's already in the list having its own webResources config + if (!filteredWebResources.contains(warSourceDir) && isFilteringDeploymentDescriptors(project)) { + retVal.add(warSourceDir); + } + + return retVal; + } + + /** + * @param project + * + * @return List of webResources/resource configurations with filtering enabled, whether they happen to be the war source directory + * or not + */ + private static Set getFilteredWebResourcesConfigurations(MavenProject project) { + Set retVal = new HashSet(); Path baseDirPath = Paths.get(project.getBasedir().getAbsolutePath()); for (Xpp3Dom resource : getWebResourcesConfigurations(project)) { @@ -119,18 +137,11 @@ public static List getFilteredWebSourceDirectories(MavenProject project) { } } - // Now add warSourceDir - if (isFilteringDeploymentDescriptors(project)) { - retVal.add(getWarSourceDirectory(project)); - } - return retVal; } - - public List getFilteredWebSourceDirectories() { - return getFilteredWebSourceDirectories(project); - } - + + + private static boolean isFilteringDeploymentDescriptors(MavenProject project) { Boolean retVal = false; Xpp3Dom dom = project.getGoalConfiguration("org.apache.maven.plugins", "maven-war-plugin", null, null); @@ -232,7 +243,14 @@ public static List getWebResourcesConfigurations(MavenProject project) return retVal; } - private void addWebResourcesConfigurationPaths(boolean onlyUnfiltered) throws DOMException, IOException { + /* + * Add loose app XML elements for each directory within a maven-war-plugin configuration/webResources/resource/directory element + * + * @return + * @throws IOException + * @throws DOMException + */ + public void addAllWebResourcesConfigurationPaths() throws DOMException, IOException { Set handled = new HashSet(); Path baseDirPath = Paths.get(project.getBasedir().getAbsolutePath()); @@ -240,37 +258,62 @@ private void addWebResourcesConfigurationPaths(boolean onlyUnfiltered) throws DO for (Xpp3Dom resource : getWebResourcesConfigurations(project)) { Xpp3Dom dir = resource.getChild("directory"); Xpp3Dom target = resource.getChild("targetPath"); - Xpp3Dom filtering = resource.getChild("filtering"); Path resolvedDir = baseDirPath.resolve(dir.getValue()); if (handled.contains(resolvedDir)) { log.warn("Ignoring webResources dir: " + dir.getValue() + ", already have entry for path: " + resolvedDir); } else { - if (onlyUnfiltered && filtering != null && Boolean.parseBoolean(filtering.getValue())) { - continue; - } else { - String targetPath = "/"; - if (target != null) { - targetPath = "/" + target.getValue(); - } - addOutputDir(getDocumentRoot(), resolvedDir.toFile(), targetPath); - handled.add(resolvedDir); - } + String targetPath = "/"; + if (target != null) { + targetPath = "/" + target.getValue(); + } + addOutputDir(getDocumentRoot(), resolvedDir.toFile(), targetPath); + handled.add(resolvedDir); } } } /* + * Add loose app XML elements for the WAR source directory, as long as it is not filtered, and for each non-filtered + * maven-war-plugin configuration/webResources/resource/directory element + * * @return * @throws IOException * @throws DOMException */ + public void addNonFilteredSourceAndWebResourcesPaths() throws DOMException, IOException { - public void addAllWebResourcesConfigurationPaths() throws DOMException, IOException { - addWebResourcesConfigurationPaths(false); - } + // Write the source dir first, out of tradition/precedence + if (!isFilteringDeploymentDescriptors() && !getFilteredWebResourcesConfigurations(project).contains(warSourceDirectory)) { + addSourceDir(); + } + + Path baseDirPath = Paths.get(project.getBasedir().getAbsolutePath()); - public void addNonFilteredWebResourcesConfigurationPaths() throws DOMException, IOException { - addWebResourcesConfigurationPaths(true); + Set handled = new HashSet(); // Use to warn for duplicate entries + for (Xpp3Dom resource : getWebResourcesConfigurations(project)) { + Xpp3Dom dir = resource.getChild("directory"); + Xpp3Dom target = resource.getChild("targetPath"); + Xpp3Dom filtering = resource.getChild("filtering"); + Path resolvedDir = baseDirPath.resolve(dir.getValue()); + if (resolvedDir.equals(warSourceDirectory)) { + // We have already decided to write the source dir or not above + continue; + } + if (filtering != null && Boolean.parseBoolean(filtering.getValue())) { + continue; + } else { + if (handled.contains(resolvedDir)) { + log.warn("Ignoring webResources dir: " + dir.getValue() + ", already have entry for path: " + resolvedDir); + } else { + String targetPath = "/"; + if (target != null) { + targetPath = "/" + target.getValue(); + } + addOutputDir(getDocumentRoot(), resolvedDir.toFile(), targetPath); + handled.add(resolvedDir); + } + } + } } public Path getWebAppDirectory() { diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java index d0559beb9..5466ecfe0 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/DevMojo.java @@ -25,6 +25,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -783,8 +784,9 @@ protected void updateLooseApp() throws PluginExecutionException { // Validate maven-war-plugin version Plugin warPlugin = getPlugin("org.apache.maven.plugins", "maven-war-plugin"); - if (!validatePluginVersion(warPlugin.getVersion(), "3.3.1")) { - getLog().warn("Exploded WAR functionality is enabled. Please use maven-war-plugin version 3.3.1 or greater for best results."); + if (!validatePluginVersion(warPlugin.getVersion(), "3.3.2")) { + getLog().warn( + "Exploded WAR functionality is enabled. Please use maven-war-plugin version 3.3.2 or greater for best results."); } redeployApp(); @@ -821,20 +823,30 @@ protected void resourceDirectoryCreated() throws IOException { @Override protected void resourceModifiedOrCreated(File fileChanged, File resourceParent, File outputDirectory) throws IOException { - if (project.getPackaging().equals("war") && LooseWarApplication.isExploded(project)) { - try { - runMojo("org.apache.maven.plugins", "maven-resources-plugin", "resources"); - runExplodedMojo(); - } catch (MojoExecutionException e) { - getLog().error("Failed to run goal(s)", e); - } - } else { - copyFile(fileChanged, resourceParent, outputDirectory, null); + /** + * There is an asymmetry here that we take advantage of in the exploded case. For multi-mod, this would be a copyFile, which + * does not apply Maven filters. + */ + try { + runMojo("org.apache.maven.plugins", "maven-resources-plugin", "resources"); + } catch (MojoExecutionException e) { + getLog().error("Failed to run goal(s)", e); } } @Override protected void resourceDeleted(File fileChanged, File resourceParent, File outputDirectory) throws IOException { + + /** + * Why is this so asymmetric compared to resourceModifiedOrCreated() above? For two reasons: 1. The resources:resources plugin + * goal doesn't update the target/output directory with deletions, so we have to use our own custom deleteFile() method 2. In + * the case of the exploded loose app format, even having deleted the file from the outputDirectory ('target/classes'), the + * resource would typically also have been collected into the exploded 'webapp' directory. Even though it would take precedence + * in 'target/classes' when it ends up in both locations, it will still be present in the 'webapp' directory. So we re-run the + * exploded goal to force an "outdated" update cleaning this file from this location. Another approach might have been to do a + * delteFile() in the 'webapp' directory. + */ + deleteFile(fileChanged, resourceParent, outputDirectory, null); if (project.getPackaging().equals("war") && LooseWarApplication.isExploded(project)) { try { @@ -871,10 +883,12 @@ public boolean recompileBuildFile(File buildFile, Set compileArtifactPat // set the updated project in current session; Plugin backupLibertyPlugin = getLibertyPlugin(); + Plugin backupWarPlugin = getPluginForProject("org.apache.maven.plugins", "maven-war-plugin", project); MavenProject backupProject = project; project = build.getProject(); session.setCurrentProject(project); Plugin libertyPlugin = getLibertyPlugin(); + Plugin warPlugin = getPluginForProject("org.apache.maven.plugins", "maven-war-plugin", project); try { // TODO rebuild the corresponding module if the compiler options have changed @@ -916,6 +930,11 @@ public boolean recompileBuildFile(File buildFile, Set compileArtifactPat if (!Objects.equals(config, oldConfig)) { redeployApp = true; } + config = ExecuteMojoUtil.getPluginGoalConfig(warPlugin, "exploded", getLog()); + oldConfig = ExecuteMojoUtil.getPluginGoalConfig(backupWarPlugin, "exploded", getLog()); + if (!Objects.equals(config, oldConfig) || !warPlugin.getVersion().equals(backupWarPlugin.getVersion())) { + redeployApp = true; + } config = ExecuteMojoUtil.getPluginGoalConfig(libertyPlugin, "generate-features", getLog()); oldConfig = ExecuteMojoUtil.getPluginGoalConfig(backupLibertyPlugin, "generate-features", getLog()); if (!Objects.equals(config, oldConfig)) { @@ -967,6 +986,25 @@ public boolean recompileBuildFile(File buildFile, Set compileArtifactPat } } + + // We don't currently have the ability to dynamically add new directories to be watched + // There is so much that we are dynamically able to do that this could be surprising. + // For now issue a warning + Set oldMonitoredWebResourceDirs = new HashSet(this.monitoredWebResourceDirs); + Set newMonitoredWebResourceDirs = new HashSet(LooseWarApplication.getWebSourceDirectoriesToMonitor(project)); + if (!oldMonitoredWebResourceDirs.equals(newMonitoredWebResourceDirs)) { + getLog().warn("Change detected in the set of filtered web resource directories, since dev mode was first launched. Adding/deleting a web resource directory has no change on the set of directories monitored by dev mode. Changing the watch list will require a dev mode restart"); + } + + // convert to Path, which seems to offer more reliable cross-platform, relative path comparison, then compare + Set oldResourceDirs = new HashSet(); + this.resourceDirs.forEach(r -> oldResourceDirs.add(r.toPath())); + Set newResourceDirs = new HashSet(); + project.getResources().forEach(r -> newResourceDirs.add(Paths.get(r.getDirectory()))); + if (!oldResourceDirs.equals(newResourceDirs)) { + getLog().warn("Change detected in the set of resource directories, since dev mode was first launched. Adding/deleting a resource directory has no change on the set of directories monitored by dev mode. Changing the watch list will require a dev mode restart"); + } + if (restartServer) { // - stop Server // - create server or runBoostMojo @@ -1359,7 +1397,7 @@ private void doDevMode() throws MojoExecutionException { // resource directories List resourceDirs = getResourceDirectories(project, outputDirectory); - List webResourceDirs = LooseWarApplication.getFilteredWebSourceDirectories(project); + List webResourceDirs = LooseWarApplication.getWebSourceDirectoriesToMonitor(project); JavaCompilerOptions compilerOptions = getMavenCompilerOptions(project); diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java index 4199d251f..c8fdce107 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/server/StartDebugMojoSupport.java @@ -207,9 +207,14 @@ protected void runExplodedMojo() throws MojoExecutionException { Plugin warPlugin = getPlugin("org.apache.maven.plugins", "maven-war-plugin"); Xpp3Dom explodedConfig = ExecuteMojoUtil.getPluginGoalConfig(warPlugin, "exploded", getLog()); - if (validatePluginVersion(warPlugin.getVersion(), "3.3.1")) { - explodedConfig.addChild(element(name("outdatedCheckPath"), "WEB-INF").toDom()); + if (explodedConfig.getChild("outdatedCheckPath") == null) { + if (validatePluginVersion(warPlugin.getVersion(), "3.3.2")) { + explodedConfig.addChild(element(name("outdatedCheckPath"), "/").toDom()); + } else if (validatePluginVersion(warPlugin.getVersion(), "3.3.1")) { + explodedConfig.addChild(element(name("outdatedCheckPath"), "WEB-INF").toDom()); + } } + getLog().info("Running maven-war-plugin:exploded"); getLog().debug("configuration:\n" + explodedConfig); session.getRequest().setStartTime(new Date()); diff --git a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/utils/ExecuteMojoUtil.java b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/utils/ExecuteMojoUtil.java index 2627503b3..bb6560d2c 100644 --- a/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/utils/ExecuteMojoUtil.java +++ b/liberty-maven-plugin/src/main/java/io/openliberty/tools/maven/utils/ExecuteMojoUtil.java @@ -139,9 +139,17 @@ public class ExecuteMojoUtil { private static final ArrayList FAILSAFE_REPORT_ONLY_PARAMS = REPORT_ONLY_PARAMS; // https://maven.apache.org/plugins/maven-war-plugin/exploded-mojo.html + // as of Version: 3.4.1-SNAPSHOT, 2023-06-11 private static final ArrayList EXPLODED_PARAMS = new ArrayList<>(Arrays.asList( - "filteringDeploymentDescriptors", "warSourceDirectory", "webappDirectory", "workDirectory", "filters", - "overlays", "webResources" + // Required + "warSourceDirectory", "webappDirectory", "workDirectory", + // Optional - skip archive* options which may not make sense with our loose app approach + "containerConfigXML", "delimiters", "dependentWarExcludes", + "dependentWarIncludes", "escapedBackslashesInFilePath", "escapeString", "failOnMissingWebXml", + "filteringDeploymentDescriptors", "filters", "includeEmptyDirectories", "nonFilteredFileExtensions", + "outdatedCheckPath", "outputFileNameMapping", "outputTimestamp", "overlays", "propertiesEncoding", "recompressZippedFiles", + "resourceEncoding", "supportMultiLineFiltering", "useDefaultDelimiters", "useJvmChmod", "warSourceExcludes", "warSourceIncludes", + "webResources", "webXml" )); // https://maven.apache.org/plugins/maven-ear-plugin/ear-mojo.html