/**
* 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.portal.library;
import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.PropertiesUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author Matthew Tambara
* @author Shuyang Zhou
* @author Andrea Di Giorgi
*/
public class LibraryReferenceTest {
@BeforeClass
public static void setUpClass() throws Exception {
_portalPath = Paths.get(System.getProperty("user.dir"));
_initGitIgnoreJars();
_initLibJars();
_initModuleSourceDirs();
DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder =
documentBuilderFactory.newDocumentBuilder();
_initEclipse(documentBuilder);
_initNetBeans(documentBuilder);
_initVersionsJars(documentBuilder);
}
@Test
public void testEclipseJarsInLib() {
testNonexistentJarReferences(_eclipseJars, _ECLIPSE_FILE_NAME);
}
@Test
public void testEclipseSourceDirsInModules() {
testNonexistentModuleSourceDirReferences(
_eclipseModuleSourceDirs, _ECLIPSE_FILE_NAME);
}
@Test
public void testLibDependencyJarsInGitIgnore() {
testMissingJarReferences(_gitIgnoreJars, _GIT_IGNORE_FILE_NAME);
}
@Test
public void testLibJarsInEclipse() {
testMissingJarReferences(_eclipseJars, _ECLIPSE_FILE_NAME);
}
@Test
public void testLibJarsInNetBeans() {
testMissingJarReferences(_netBeansJars, _NETBEANS_FILE_NAME);
}
@Test
public void testLibJarsInVersions() {
testMissingJarReferences(_versionsJars, _VERSIONS_FILE_NAME);
}
@Test
public void testModulesSourceDirsInEclipse() {
testMissingModuleSourceDirReferences(
_eclipseModuleSourceDirs, _ECLIPSE_FILE_NAME);
}
@Test
public void testModulesSourceDirsInNetBeans() {
testMissingModuleSourceDirReferences(
_netBeansModuleSourceDirs, _NETBEANS_FILE_NAME);
}
@Test
public void testNetBeansJarsInLib() {
testNonexistentJarReferences(_netBeansJars, _NETBEANS_FILE_NAME);
}
@Test
public void testNetBeansSourceDirsInModules() {
testNonexistentModuleSourceDirReferences(
_netBeansModuleSourceDirs, _NETBEANS_FILE_NAME);
}
@Test
public void testVersionsJarsInLib() {
testNonexistentJarReferences(_versionsJars, _VERSIONS_FILE_NAME);
}
protected void testMissingJarReferences(Set<String> jars, String fileName) {
Set<String> libJars = _libJars;
if (fileName.equals(_GIT_IGNORE_FILE_NAME)) {
libJars = _libDependencyJars;
}
for (String jar : libJars) {
if (fileName.equals(_VERSIONS_FILE_NAME) &&
(_excludeJars.contains(jar) ||
_libDependencyJars.contains(jar))) {
continue;
}
String referenceJar = jar;
if (fileName.equals(_GIT_IGNORE_FILE_NAME)) {
referenceJar = CharPool.SLASH + referenceJar;
}
Assert.assertTrue(
fileName + " is missing a reference to " + referenceJar,
jars.contains(jar));
}
}
protected void testMissingModuleSourceDirReferences(
Set<String> dirs, String fileName) {
for (String dir : _moduleSourceDirs) {
Assert.assertTrue(
fileName + " is missing a reference to " + dir,
dirs.contains(dir));
}
}
protected void testNonexistentJarReferences(
Set<String> jars, String fileName) {
for (String jar : jars) {
if (fileName.equals(_VERSIONS_FILE_NAME)) {
Assert.assertFalse(
fileName + " has a forbidden reference to " + jar,
_libDependencyJars.contains(jar));
}
Assert.assertTrue(
fileName + " has a nonexistent reference to " + jar,
_libJars.contains(jar));
}
}
protected void testNonexistentModuleSourceDirReferences(
Set<String> dirs, String fileName) {
for (String dir : dirs) {
Assert.assertTrue(
fileName + " has a nonexistent reference to " + dir,
_moduleSourceDirs.contains(dir));
}
}
private static void _initEclipse(DocumentBuilder documentBuilder)
throws Exception {
Document document = documentBuilder.parse(new File(_ECLIPSE_FILE_NAME));
NodeList nodelist = document.getElementsByTagName("classpathentry");
for (int i = 0; i < nodelist.getLength(); i++) {
Node node = nodelist.item(i);
NamedNodeMap namedNodeMap = node.getAttributes();
Node kindNode = namedNodeMap.getNamedItem("kind");
Node pathNode = namedNodeMap.getNamedItem("path");
String kind = kindNode.getNodeValue();
String path = pathNode.getNodeValue();
if (kind.equals(_LIB_DIR_NAME)) {
_eclipseJars.add(path);
}
else if (kind.equals("src")) {
if (path.startsWith(_MODULES_DIR_NAME + CharPool.SLASH)) {
_eclipseModuleSourceDirs.add(path);
}
}
}
}
private static void _initGitIgnoreJars() throws IOException {
try (UnsyncBufferedReader unsyncBufferedReader =
new UnsyncBufferedReader(
new FileReader(new File(_GIT_IGNORE_FILE_NAME)))) {
String line = null;
while ((line = unsyncBufferedReader.readLine()) != null) {
if (line.startsWith(
CharPool.SLASH + _LIB_DIR_NAME + CharPool.SLASH)) {
_gitIgnoreJars.add(line.substring(1));
}
}
}
}
private static void _initLibJars() throws IOException {
Path libDirPath = Paths.get(_LIB_DIR_NAME);
for (String line :
Files.readAllLines(
libDirPath.resolve("versions-ignore.txt"),
Charset.forName("UTF-8"))) {
line = line.trim();
if (!line.isEmpty()) {
_excludeJars.add(line);
}
}
Files.walkFileTree(
libDirPath,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(
Path dirPath, BasicFileAttributes basicFileAttributes)
throws IOException {
Path path = dirPath.resolve("dependencies.properties");
if (Files.notExists(path)) {
return FileVisitResult.CONTINUE;
}
Properties properties;
try (InputStream inputStream = Files.newInputStream(path)) {
properties = PropertiesUtil.load(
inputStream, StringPool.UTF8);
}
String dirPathString = dirPath.toString();
if (File.separatorChar != CharPool.SLASH) {
dirPathString = dirPathString.replace(
File.separatorChar, CharPool.SLASH);
}
dirPathString += CharPool.SLASH;
for (String fileTitle : properties.stringPropertyNames()) {
String jar = dirPathString + fileTitle + ".jar";
_libDependencyJars.add(jar);
_libJars.add(jar);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(
Path path, BasicFileAttributes basicFileAttributes) {
String pathString = path.toString();
if (pathString.endsWith(".jar")) {
if (File.separatorChar != CharPool.SLASH) {
pathString = pathString.replace(
File.separatorChar, CharPool.SLASH);
}
_libJars.add(pathString);
}
return FileVisitResult.CONTINUE;
}
});
}
private static void _initModuleSourceDirs() throws IOException {
Files.walkFileTree(
_portalPath.resolve(_MODULES_DIR_NAME),
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(
Path dirPath, BasicFileAttributes basicFileAttributes) {
String dirName = String.valueOf(dirPath.getFileName());
if (!dirName.equals("util-taglib-compat") &&
Files.exists(dirPath.resolve(".lfrbuild-portal-pre"))) {
Path sourceDirPath = dirPath.resolve(
_SRC_JAVA_DIR_NAME);
String sourceDir = String.valueOf(
_portalPath.relativize(sourceDirPath));
if (File.separatorChar != CharPool.SLASH) {
sourceDir = StringUtil.replace(
sourceDir, File.separatorChar, CharPool.SLASH);
}
_moduleSourceDirs.add(sourceDir);
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
});
}
private static void _initNetBeans(DocumentBuilder documentBuilder)
throws Exception {
Document document = documentBuilder.parse(
new File(_NETBEANS_FILE_NAME));
NodeList nodelist = document.getElementsByTagName("classpath");
for (int i = 0; i < nodelist.getLength(); i++) {
Node node = nodelist.item(i);
_netBeansJars.add(node.getTextContent());
}
nodelist = document.getElementsByTagName("source-folder");
for (int i = 0; i < nodelist.getLength(); i++) {
Element element = (Element)nodelist.item(i);
NodeList locationNodeList = element.getElementsByTagName(
"location");
Node locationNode = locationNodeList.item(0);
String location = locationNode.getTextContent();
if (location.startsWith(_MODULES_DIR_NAME + CharPool.SLASH) &&
location.endsWith(CharPool.SLASH + _SRC_JAVA_DIR_NAME)) {
_netBeansModuleSourceDirs.add(location);
}
}
}
private static void _initVersionsJars(DocumentBuilder documentBuilder)
throws Exception {
Document document = documentBuilder.parse(
new File(_VERSIONS_FILE_NAME));
NodeList nodelist = document.getElementsByTagName("file-name");
for (int i = 0; i < nodelist.getLength(); i++) {
Node node = nodelist.item(i);
_versionsJars.add(node.getTextContent());
}
}
private static final String _ECLIPSE_FILE_NAME = ".classpath";
private static final String _GIT_IGNORE_FILE_NAME = ".gitignore";
private static final String _LIB_DIR_NAME = "lib";
private static final String _MODULES_DIR_NAME = "modules";
private static final String _NETBEANS_FILE_NAME = "nbproject/project.xml";
private static final String _SRC_JAVA_DIR_NAME = "src/main/java";
private static final String _VERSIONS_FILE_NAME =
_LIB_DIR_NAME + "/versions.xml";
private static final Set<String> _eclipseJars = new HashSet<>();
private static final Set<String> _eclipseModuleSourceDirs = new HashSet<>();
private static final Set<String> _excludeJars = new HashSet<>();
private static final Set<String> _gitIgnoreJars = new HashSet<>();
private static final Set<String> _libDependencyJars = new HashSet<>();
private static final Set<String> _libJars = new HashSet<>();
private static final Set<String> _moduleSourceDirs = new HashSet<>();
private static final Set<String> _netBeansJars = new HashSet<>();
private static final Set<String> _netBeansModuleSourceDirs =
new HashSet<>();
private static Path _portalPath;
private static final Set<String> _versionsJars = new HashSet<>();
}