/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.gradle.plugins.test.integration.tasks; import com.liferay.gradle.plugins.test.integration.internal.util.GradleUtil; import com.liferay.gradle.plugins.test.integration.internal.util.StringUtil; import com.liferay.gradle.util.FileUtil; import com.liferay.gradle.util.copy.ExcludeExistingFileAction; import com.liferay.gradle.util.copy.StripPathSegmentsAction; import groovy.xml.DOMBuilder; import groovy.xml.XmlUtil; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import org.gradle.api.Action; import org.gradle.api.DefaultTask; import org.gradle.api.Project; import org.gradle.api.file.CopySpec; import org.gradle.api.logging.Logger; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.TaskAction; import org.gradle.util.VersionNumber; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * @author Andrea Di Giorgi */ public class SetUpTestableTomcatTask extends DefaultTask implements JmxRemotePortSpec, ManagerSpec, ModuleFrameworkBaseDirSpec { public SetUpTestableTomcatTask() { _zipUrl = new Callable<String>() { @Override public String call() throws Exception { File dir = getDir(); String dirName = dir.getName(); int start = StringUtil.indexOfDigit(dirName); if (start < 0) { return null; } VersionNumber versionNumber = VersionNumber.parse( dirName.substring(start)); if (versionNumber == VersionNumber.UNKNOWN) { return null; } StringBuilder sb = new StringBuilder(); sb.append("http://archive.apache.org/dist/tomcat/tomcat-"); sb.append(versionNumber.getMajor()); sb.append("/v"); sb.append(versionNumber); sb.append("/bin/apache-tomcat-"); sb.append(versionNumber); sb.append(".zip"); return sb.toString(); } }; } public SetUpTestableTomcatTask catalinaOptsReplacement( String oldSub, Object newSub) { _catalinaOptsReplacements.put(oldSub, newSub); return this; } public SetUpTestableTomcatTask catalinaOptsReplacements( Map<String, ?> catalinaOptsReplacements) { _catalinaOptsReplacements.putAll(catalinaOptsReplacements); return this; } public File getBinDir() { return new File(getDir(), "bin"); } @Input public Map<String, Object> getCatalinaOptsReplacements() { return _catalinaOptsReplacements; } @Input public File getDir() { return GradleUtil.toFile(getProject(), _dir); } @Input @Override public int getJmxRemotePort() { return GradleUtil.toInteger(_jmxRemotePort); } @Input @Override public String getManagerPassword() { return GradleUtil.toString(_managerPassword); } @Input @Override public String getManagerUserName() { return GradleUtil.toString(_managerUserName); } @Input @Override public File getModuleFrameworkBaseDir() { return GradleUtil.toFile(getProject(), _moduleFrameworkBaseDir); } @Input public String getZipUrl() { return GradleUtil.toString(_zipUrl); } @Input public boolean isDebugLogging() { return _debugLogging; } @Input public boolean isJmxRemoteAuthenticate() { return _jmxRemoteAuthenticate; } @Input public boolean isJmxRemoteSsl() { return _jmxRemoteSsl; } @Input public boolean isOverwriteTestModules() { return _overwriteTestModules; } public void setCatalinaOptsReplacements( Map<String, ?> catalinaOptsReplacements) { _catalinaOptsReplacements.clear(); catalinaOptsReplacements(catalinaOptsReplacements); } public void setDebugLogging(boolean debugLogging) { _debugLogging = debugLogging; } public void setDir(Object dir) { _dir = dir; } public void setJmxRemoteAuthenticate(boolean jmxRemoteAuthenticate) { _jmxRemoteAuthenticate = jmxRemoteAuthenticate; } @Override public void setJmxRemotePort(Object jmxRemotePort) { _jmxRemotePort = jmxRemotePort; } public void setJmxRemoteSsl(boolean jmxRemoteSsl) { _jmxRemoteSsl = jmxRemoteSsl; } @Override public void setManagerPassword(Object managerPassword) { _managerPassword = managerPassword; } @Override public void setManagerUserName(Object managerUserName) { _managerUserName = managerUserName; } @Override public void setModuleFrameworkBaseDir(Object moduleFrameworkBaseDir) { _moduleFrameworkBaseDir = moduleFrameworkBaseDir; } public void setOverwriteTestModules(boolean overwriteTestModules) { _overwriteTestModules = overwriteTestModules; } @TaskAction public void setUpTestableTomcat() throws Exception { _setUpCatalinaOpts(); _setUpJmx(); _setUpLogging(); _setUpManager(); _setUpOsgiModules(); } public void setZipUrl(Object zipUrl) { _zipUrl = zipUrl; } private boolean _contains(String fileName, String s) throws IOException { File file = new File(getDir(), fileName); String fileContent = new String(Files.readAllBytes(file.toPath())); if (fileContent.contains(s)) { return true; } return false; } private PrintWriter _getAppendPrintWriter(String fileName) throws IOException { File file = new File(getDir(), fileName); return new PrintWriter( Files.newBufferedWriter( file.toPath(), StandardCharsets.UTF_8, StandardOpenOption.APPEND, StandardOpenOption.WRITE)); } private String _getJmxOptions() { StringBuilder sb = new StringBuilder(); sb.append("-Dcom.sun.management.jmxremote "); sb.append("-Dcom.sun.management.jmxremote.authenticate="); sb.append(isJmxRemoteAuthenticate()); sb.append(" -Dcom.sun.management.jmxremote.port="); sb.append(getJmxRemotePort()); sb.append(" -Dcom.sun.management.jmxremote.ssl="); sb.append(isJmxRemoteSsl()); return sb.toString(); } private void _replace(String fileName, Map<String, Object> replacements) throws IOException { Logger logger = getLogger(); File dir = getDir(); Path dirPath = dir.toPath(); Path path = dirPath.resolve(fileName); String content = new String(Files.readAllBytes(path)); for (Map.Entry<String, Object> entry : replacements.entrySet()) { String oldSub = entry.getKey(); String newSub = GradleUtil.toString(entry.getValue()); if (logger.isWarnEnabled() && !content.contains(oldSub)) { logger.warn("Unable to find \"{}\" in {}", oldSub, path); } content = content.replace(oldSub, newSub); } Files.write(path, content.getBytes()); } private void _setUpCatalinaOpts() throws IOException { Map<String, Object> replacements = getCatalinaOptsReplacements(); if (replacements.isEmpty()) { return; } _replace("bin/setenv.bat", replacements); _replace("bin/setenv.sh", replacements); } private void _setUpJmx() throws IOException { String jmxOptions = _getJmxOptions(); if (!_contains("bin/setenv.bat", jmxOptions)) { try (PrintWriter printWriter = _getAppendPrintWriter( "bin/setenv.bat")) { printWriter.println(); printWriter.print("set \"JMX_OPTS="); printWriter.print(jmxOptions); printWriter.println('\"'); printWriter.println(); printWriter.println( "set \"CATALINA_OPTS=%CATALINA_OPTS% %JMX_OPTS%\""); } } if (!_contains("bin/setenv.sh", jmxOptions)) { try (PrintWriter printWriter = _getAppendPrintWriter( "bin/setenv.sh")) { printWriter.println(); printWriter.print("JMX_OPTS=\""); printWriter.print(jmxOptions); printWriter.println('\"'); printWriter.println(); printWriter.println( "CATALINA_OPTS=\"${CATALINA_OPTS} ${JMX_OPTS}\""); } } } private void _setUpLogging() throws IOException { if (!isDebugLogging() || _contains("conf/Logging.properties", "org.apache.catalina.level")) { return; } try (PrintWriter printWriter = _getAppendPrintWriter( "conf/Logging.properties")) { printWriter.println("org.apache.catalina.level=ALL"); printWriter.println(); printWriter.println( "org.apache.catalina.loader.WebappClassLoader.level=INFO"); printWriter.println( "org.apache.catalina.loader.WebappLoader.level=INFO"); printWriter.println( "org.apache.catalina.startup.ClassLoaderFactory.level=INFO"); } } private void _setUpManager() throws Exception { final File managerDir = new File(getDir(), "webapps/manager"); if (!managerDir.exists()) { final Project project = getProject(); final File zipFile = FileUtil.get(project, getZipUrl()); project.copy( new Action<CopySpec>() { @Override public void execute(CopySpec copySpec) { copySpec.eachFile(new StripPathSegmentsAction(2)); copySpec.from(project.zipTree(zipFile)); copySpec.include( "apache-tomcat-*/webapps/manager/**/*"); copySpec.into(managerDir.getParentFile()); copySpec.setIncludeEmptyDirs(false); } }); } Document document = null; final File tomcatUsersXmlFile = new File( getDir(), "conf/tomcat-users.xml"); try (InputStreamReader inputStreamReader = new InputStreamReader( new FileInputStream(tomcatUsersXmlFile))) { document = DOMBuilder.parse(inputStreamReader); } Element tomcatUsersElement = document.getDocumentElement(); Set<String> existentRoleNames = new HashSet<>(); boolean tomcatManagerUserExists = false; NodeList nodeList = tomcatUsersElement.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() != Node.ELEMENT_NODE) { continue; } Element element = (Element)node; String elementName = element.getNodeName(); if (elementName.equals("role")) { String roleName = element.getAttribute("rolename"); existentRoleNames.add(roleName); } else if (elementName.equals("user")) { String userName = element.getAttribute("username"); if (userName.equals(getManagerUserName())) { tomcatManagerUserExists = true; } } } boolean tomcatUsersXmlFileModified = false; for (String roleName : _TOMCAT_USERS_ROLE_NAMES) { if (!existentRoleNames.contains(roleName)) { Element element = document.createElement("role"); element.setAttribute("rolename", roleName); tomcatUsersElement.appendChild(element); tomcatUsersXmlFileModified = true; } } if (!tomcatManagerUserExists) { Element element = document.createElement("user"); element.setAttribute("password", getManagerPassword()); element.setAttribute( "roles", "tomcat,manager-gui,manager-script,manager-jmx,manager-status"); element.setAttribute("username", getManagerUserName()); tomcatUsersElement.appendChild(element); tomcatUsersXmlFileModified = true; } if (tomcatUsersXmlFileModified) { Path timestampTomcatUserXmlFilePath = Paths.get( tomcatUsersXmlFile.toString() + "." + _timestampDateFormat.format(new Date())); Files.copy( tomcatUsersXmlFile.toPath(), timestampTomcatUserXmlFilePath); try (FileOutputStream fileOutputStream = new FileOutputStream( tomcatUsersXmlFile)) { XmlUtil.serialize(tomcatUsersElement, fileOutputStream); } } } private void _setUpOsgiModules() { Project project = getProject(); project.copy( new Action<CopySpec>() { @Override public void execute(CopySpec copySpec) { File moduleFrameworkBaseDir = getModuleFrameworkBaseDir(); File modulesDir = new File( moduleFrameworkBaseDir, "modules"); if (!isOverwriteTestModules()) { copySpec.eachFile( new ExcludeExistingFileAction(modulesDir)); } copySpec.from(new File(moduleFrameworkBaseDir, "test")); copySpec.into(modulesDir); } }); } private static final String[] _TOMCAT_USERS_ROLE_NAMES = { "manager-gui", "manager-jmx", "manager-script", "manager-status", "tomcat" }; private final Map<String, Object> _catalinaOptsReplacements = new LinkedHashMap<>(); private boolean _debugLogging; private Object _dir; private boolean _jmxRemoteAuthenticate; private Object _jmxRemotePort; private boolean _jmxRemoteSsl; private Object _managerPassword; private Object _managerUserName; private Object _moduleFrameworkBaseDir; private boolean _overwriteTestModules; private final DateFormat _timestampDateFormat = new SimpleDateFormat( "yyyyMMddkkmmssSSS"); private Object _zipUrl; }