From c7f1e89c741cc4f2e9a71d4a9c3e263e67bee128 Mon Sep 17 00:00:00 2001 From: Matt Bowersox Date: Mon, 20 Feb 2023 15:52:13 -0600 Subject: [PATCH] Fix loose app generation for jar project dependencies in war projects --- .../tools/gradle/tasks/DeployTask.groovy | 41 ++++-- .../gradle/TestLooseWarWithLooseJar.groovy | 135 ++++++++++++++++++ .../loose-war-with-loose-jar/build.gradle | 19 +++ .../ejb-ejb/build.gradle | 10 ++ .../wasdev/ejb/ejb/SampleStatelessBean.java | 11 ++ .../ejb-war/build.gradle | 41 ++++++ .../java/wasdev/ejb/ejb/web/EJBServlet.java | 34 +++++ .../ejb-war/src/main/webapp/WEB-INF/web.xml | 0 .../loose-war-with-loose-jar/settings.gradle | 6 + 9 files changed, 283 insertions(+), 14 deletions(-) create mode 100644 src/test/groovy/io/openliberty/tools/gradle/TestLooseWarWithLooseJar.groovy create mode 100644 src/test/resources/loose-war-with-loose-jar/build.gradle create mode 100644 src/test/resources/loose-war-with-loose-jar/ejb-ejb/build.gradle create mode 100644 src/test/resources/loose-war-with-loose-jar/ejb-ejb/src/main/java/wasdev/ejb/ejb/SampleStatelessBean.java create mode 100644 src/test/resources/loose-war-with-loose-jar/ejb-war/build.gradle create mode 100644 src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/java/wasdev/ejb/ejb/web/EJBServlet.java create mode 100644 src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/webapp/WEB-INF/web.xml create mode 100644 src/test/resources/loose-war-with-loose-jar/settings.gradle diff --git a/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy b/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy index 40ce7fbd8..71c45aadf 100644 --- a/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy +++ b/src/main/groovy/io/openliberty/tools/gradle/tasks/DeployTask.groovy @@ -1,5 +1,5 @@ /** - * (C) Copyright IBM Corporation 2014, 2021. + * (C) Copyright IBM Corporation 2014, 2023. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -347,26 +347,39 @@ class DeployTask extends AbstractServerTask { private void addWarEmbeddedLib(Element parent, LooseWarApplication looseApp, Task task) throws Exception { ArrayList deps = new ArrayList(); - task.classpath.each {deps.add(it)} + task.classpath.each { + deps.add(it) + } //Removes WEB-INF/lib/main directory since it is not rquired in the xml - if(deps != null && !deps.isEmpty()) { + if (deps != null && !deps.isEmpty()) { deps.remove(0) } File parentProjectDir = new File(task.getProject().getRootProject().rootDir.getAbsolutePath()) for (File dep: deps) { - String dependentProjectName = "project ':"+getProjectPath(parentProjectDir, dep)+"'" - Project siblingProject = project.getRootProject().findProject(dependentProjectName) - boolean isCurrentProject = ((task.getProject().toString()).equals(dependentProjectName)) - if (!isCurrentProject && siblingProject != null){ - Element archive = looseApp.addArchive(parent, "/WEB-INF/lib/"+ dep.getName()); - looseApp.addOutputDirectory(archive, siblingProject, "/"); - Task resourceTask = siblingProject.getTasks().findByPath(":"+dependentProjectName+":processResources"); - if (resourceTask.getDestinationDir() != null){ + String dependencyProjectName = getProjectPath(parentProjectDir, dep) + String projectDependencyString = "project ':" + dependencyProjectName + "'" + Project siblingProject = project.getRootProject().findProject(dependencyProjectName) + boolean isCurrentProject = ((task.getProject().toString()).equals(projectDependencyString)) + if (!isCurrentProject && siblingProject != null) { + Element archive = looseApp.addArchive(parent, "/WEB-INF/lib/" + dep.getName()); + //Add sibling project class directories to as + siblingProject.sourceSets.main.getOutput().getClassesDirs().each { + looseApp.getConfig().addDir(archive, it, "/"); + } + Task resourceTask = siblingProject.getTasks().findByPath(":" + projectDependencyString + ":processResources"); + if (resourceTask != null && resourceTask.getDestinationDir() != null) { looseApp.addOutputDir(archive, resourceTask.getDestinationDir(), "/"); } - File manifestFile = project.sourceSets.main.getOutput().getResourcesDir().getParentFile() - looseApp.addManifestFileWithParent(archive, manifestFile); - } else if(FilenameUtils.getExtension(dep.getAbsolutePath()).equalsIgnoreCase("jar")){ + File resourceDir = siblingProject.sourceSets.main.getOutput().getResourcesDir() + File manifestFile = null + if (resourceDir.exists() && resourceDir.listFiles().length > 0) { + File metaInfDir = new File(resourceDir, "META-INF") + if (metaInfDir.exists() && metaInfDir.listFiles().length > 0) { + manifestFile = new File(metaInfDir, "MANIFEST.MF") + } + } + looseApp.addManifestFileWithParent(archive, manifestFile, resourceDir.getParentFile().getCanonicalPath()); + } else if (FilenameUtils.getExtension(dep.getAbsolutePath()).equalsIgnoreCase("jar")) { addLibrary(parent, looseApp, "/WEB-INF/lib/", dep); } else { looseApp.addOutputDir(looseApp.getDocumentRoot(), dep , "/WEB-INF/classes/"); diff --git a/src/test/groovy/io/openliberty/tools/gradle/TestLooseWarWithLooseJar.groovy b/src/test/groovy/io/openliberty/tools/gradle/TestLooseWarWithLooseJar.groovy new file mode 100644 index 000000000..cf91e83df --- /dev/null +++ b/src/test/groovy/io/openliberty/tools/gradle/TestLooseWarWithLooseJar.groovy @@ -0,0 +1,135 @@ +package io.openliberty.tools.gradle; + +import org.junit.AfterClass +import org.junit.BeforeClass +import org.junit.Test + +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; + +public class TestLooseWarWithLooseJar extends AbstractIntegrationTest{ + static File resourceDir = new File("build/resources/test/loose-war-with-loose-jar") + static File buildDir = new File(integTestDir, "/loose-war-with-loose-jar") + static String buildFilename = "build.gradle" + + @BeforeClass + public static void setup() { + createDir(buildDir) + createTestProject(buildDir, resourceDir, buildFilename) + } + + @Test + public void test_loose_config_file_exists() { + try { + runTasks(buildDir, 'deploy') + } catch (Exception e) { + throw new AssertionError ("Fail on task deploy. " + e) + } + assert new File('build/testBuilds/loose-war-with-loose-jar/ejb-war/build/wlp/usr/servers/testServer/apps/ejb-war.war.xml').exists() : 'looseApplication config file was not copied over to the liberty runtime' + } + + /* + Expected output to the XML + + + + + + + + + + + + + + */ + @Test + public void test_loose_config_file_contents_are_correct() { + File on = new File("build/testBuilds/loose-war-with-loose-jar/ejb-war/build/wlp/usr/servers/testServer/apps/ejb-war.war.xml"); + FileInputStream input = new FileInputStream(on); + + // 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(); + + //Check for correct number of dir elements in loose war + String expression = "/archive/dir"; + NodeList nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 2, nodes.getLength()); + + //Check loose jar archive element is present + expression = "/archive/archive"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 1, nodes.getLength()); + + //Check loose jar targetLocation is correct + Assert.assertEquals("sibling archive targetInArchive attribute value", "/WEB-INF/lib/ejb-ejb.jar", + nodes.item(0).getAttributes().getNamedItem("targetInArchive").getNodeValue()); + + //Check loose jar contains correct amount of dir elements + expression = "/archive/archive/dir"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 1, nodes.getLength()); + + //Check loose jar classes dir location + String nodeValue = nodes.item(0).getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + Assert.assertEquals("sibling archive targetInArchive attribute value", buildDir.getCanonicalPath() + "/ejb-ejb/build/classes/java/main", + nodes.item(0).getAttributes().getNamedItem("sourceOnDisk").getNodeValue()); + + //Check loose jar contains correct amount of file elements + expression = "/archive/archive/file"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 1, nodes.getLength()); + + //Check loose jar manifest file location + nodeValue = nodes.item(0).getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + Assert.assertEquals("sibling archive targetInArchive attribute value", buildDir.getCanonicalPath() + "/ejb-ejb/build/resources/tmp/META-INF/MANIFEST.MF", + nodes.item(0).getAttributes().getNamedItem("sourceOnDisk").getNodeValue()); + + //Check correct number of additional file elements are present + expression = "/archive/file"; + nodes = (NodeList) xPath.compile(expression).evaluate(inputDoc, XPathConstants.NODESET); + Assert.assertEquals("Number of element ==>", 4, nodes.getLength()); + + Assert.assertEquals("archive targetInArchive attribute value", "/WEB-INF/lib/javaee-api-7.0.jar", + nodes.item(0).getAttributes().getNamedItem("targetInArchive").getNodeValue()); + + // Check that dependencies are not located in the test build dir since copyLibsDirectory not set. They will be located in the gradle cache somewhere. + nodeValue = nodes.item(0).getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + assert nodeValue.endsWith("/javaee-api-7.0.jar") && !nodeValue.contains("/loose-war-with-loose-jar/") : 'archive sourceOnDisk attribute value not correct' + + Assert.assertEquals("archive targetInArchive attribute value", "/WEB-INF/lib/javax.mail-1.5.0.jar", + nodes.item(1).getAttributes().getNamedItem("targetInArchive").getNodeValue()); + + // Check that dependencies are not located in the test build dir since copyLibsDirectory not set. They will be located in the gradle cache somewhere. + nodeValue = nodes.item(1).getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + assert nodeValue.endsWith("/javax.mail-1.5.0.jar") && !nodeValue.contains("/loose-war-with-loose-jar/") : 'archive sourceOnDisk attribute value not correct' + + Assert.assertEquals("archive targetInArchive attribute value", "/WEB-INF/lib/activation-1.1.jar", + nodes.item(2).getAttributes().getNamedItem("targetInArchive").getNodeValue()); + + // Check that dependencies are not located in the test build dir since copyLibsDirectory not set. They will be located in the gradle cache somewhere. + nodeValue = nodes.item(2).getAttributes().getNamedItem("sourceOnDisk").getNodeValue(); + assert nodeValue.endsWith("/activation-1.1.jar") && !nodeValue.contains("/loose-war-with-loose-jar/") : 'archive sourceOnDisk attribute value not correct' + } +} diff --git a/src/test/resources/loose-war-with-loose-jar/build.gradle b/src/test/resources/loose-war-with-loose-jar/build.gradle new file mode 100644 index 000000000..b3b8c8012 --- /dev/null +++ b/src/test/resources/loose-war-with-loose-jar/build.gradle @@ -0,0 +1,19 @@ +allprojects { + group = 'sample' + version = '1.0' +} + +subprojects { + apply plugin: 'java' + + sourceCompatibility = 1.8 + targetCompatibility = 1.8 + tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' + } + + repositories { + mavenLocal() + mavenCentral() + } +} diff --git a/src/test/resources/loose-war-with-loose-jar/ejb-ejb/build.gradle b/src/test/resources/loose-war-with-loose-jar/ejb-ejb/build.gradle new file mode 100644 index 000000000..1affc981c --- /dev/null +++ b/src/test/resources/loose-war-with-loose-jar/ejb-ejb/build.gradle @@ -0,0 +1,10 @@ +description = 'EJB Module' + +dependencies { + testImplementation group: 'junit', name: 'junit', version:'4.13.1' + implementation group: 'javax', name: 'javaee-api', version:'7.0' +} + +jar { + archiveName = baseName + '.' + extension +} diff --git a/src/test/resources/loose-war-with-loose-jar/ejb-ejb/src/main/java/wasdev/ejb/ejb/SampleStatelessBean.java b/src/test/resources/loose-war-with-loose-jar/ejb-ejb/src/main/java/wasdev/ejb/ejb/SampleStatelessBean.java new file mode 100644 index 000000000..f41bfd4e5 --- /dev/null +++ b/src/test/resources/loose-war-with-loose-jar/ejb-ejb/src/main/java/wasdev/ejb/ejb/SampleStatelessBean.java @@ -0,0 +1,11 @@ +package wasdev.ejb.ejb; + +import javax.ejb.Stateless; + +@Stateless +public class SampleStatelessBean { + + public String hello() { + return "Hello EJB World."; + } +} diff --git a/src/test/resources/loose-war-with-loose-jar/ejb-war/build.gradle b/src/test/resources/loose-war-with-loose-jar/ejb-war/build.gradle new file mode 100644 index 000000000..24e8b09c6 --- /dev/null +++ b/src/test/resources/loose-war-with-loose-jar/ejb-war/build.gradle @@ -0,0 +1,41 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + maven { + name = 'Sonatype Nexus Snapshots' + url = 'https://oss.sonatype.org/content/repositories/snapshots/' + } + } + dependencies { + classpath "io.openliberty.tools:liberty-gradle-plugin:$lgpVersion" + } +} + +apply plugin: 'war' +apply plugin: 'liberty' + +jar.enabled = false +description = 'WAR Module' +dependencies { + testImplementation group: 'junit', name: 'junit', version:'4.13.1' + implementation group: 'javax', name: 'javaee-api', version:'7.0' + implementation project(':ejb-ejb') + libertyRuntime group: runtimeGroup, name: kernelArtifactId, version: runtimeVersion +} + +war { + archiveName = baseName + '.' + extension +} + +liberty { + server { + name = "testServer" + deploy { + apps = [war] + } + verifyAppStartTimeout = 30 + looseApplication = true + } +} + diff --git a/src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/java/wasdev/ejb/ejb/web/EJBServlet.java b/src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/java/wasdev/ejb/ejb/web/EJBServlet.java new file mode 100644 index 000000000..d0980c984 --- /dev/null +++ b/src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/java/wasdev/ejb/ejb/web/EJBServlet.java @@ -0,0 +1,34 @@ +package wasdev.ejb.ejb.web; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.ejb.EJB; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import wasdev.ejb.ejb.SampleStatelessBean; + +/** + * A servlet which injects a stateless EJB + */ +@WebServlet({"/", "/ejbServlet"}) +public class EJBServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @EJB + SampleStatelessBean statelessBean; + + @Override + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws IOException { + PrintWriter writer = response.getWriter(); + + // Call hello method on a stateless session bean + String message = statelessBean.hello(); + + writer.println(message); + } +} diff --git a/src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/webapp/WEB-INF/web.xml b/src/test/resources/loose-war-with-loose-jar/ejb-war/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/resources/loose-war-with-loose-jar/settings.gradle b/src/test/resources/loose-war-with-loose-jar/settings.gradle new file mode 100644 index 000000000..440f4252e --- /dev/null +++ b/src/test/resources/loose-war-with-loose-jar/settings.gradle @@ -0,0 +1,6 @@ +rootProject.name = 'ejb-war' +include ':ejb-ejb' +include ':ejb-war' + +project(':ejb-ejb').projectDir = "$rootDir/ejb-ejb" as File +project(':ejb-war').projectDir = "$rootDir/ejb-war" as File \ No newline at end of file