All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.source.formatter.checks.JavaPackagePathCheck Maven / Gradle / Ivy

There is a newer version: 1.0.1437
Show newest version
/**
 * 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.source.formatter.checks;

import com.liferay.petra.string.CharPool;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.source.formatter.BNDSettings;
import com.liferay.source.formatter.checks.util.BNDSourceUtil;
import com.liferay.source.formatter.parser.JavaClass;
import com.liferay.source.formatter.parser.JavaTerm;

import java.io.IOException;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Hugo Huijser
 */
public class JavaPackagePathCheck extends BaseJavaTermCheck {

	@Override
	protected String doProcess(
			String fileName, String absolutePath, JavaTerm javaTerm,
			String fileContent)
		throws IOException {

		if (javaTerm.getParentJavaClass() != null) {
			return javaTerm.getContent();
		}

		JavaClass javaClass = (JavaClass)javaTerm;

		if (javaClass.isAnonymous() || javaClass.hasAnnotation("Deprecated")) {
			return javaTerm.getContent();
		}

		String packageName = javaClass.getPackageName();

		if (Validator.isNull(packageName)) {
			addMessage(fileName, "Missing package");

			return javaTerm.getContent();
		}

		_checkPackageName(
			fileName, absolutePath, packageName, javaClass.getName());

		if (isModulesFile(absolutePath) && !isModulesApp(absolutePath, true)) {
			_checkModulePackageName(fileName, packageName);
		}

		_checkPackageNameByClassName(
			fileName, absolutePath, javaClass.getName(), packageName);

		if (absolutePath.contains("-api/")) {
			return javaTerm.getContent();
		}

		List expectedInternalImplementsDataEntries = getAttributeValues(
			_EXPECTED_INTERNAL_IMPLEMENTS_DATA_KEY, absolutePath);

		for (String expectedInternalImplementsDataEntry :
				expectedInternalImplementsDataEntries) {

			String[] array = StringUtil.split(
				expectedInternalImplementsDataEntry, CharPool.COLON);

			if (array.length == 2) {
				_checkInternalPackageName(
					fileName, javaClass, array[0], packageName, array[1]);
			}
		}

		return javaTerm.getContent();
	}

	@Override
	protected String[] getCheckableJavaTermNames() {
		return new String[] {JAVA_CLASS};
	}

	private void _checkInternalPackageName(
			String fileName, JavaClass javaClass, String implementedClassName,
			String packageName, String expectedPackageName)
		throws IOException {

		List implementedClassNames =
			javaClass.getImplementedClassNames();

		if (!packageName.contains(".internal.") &&
			!packageName.endsWith(".internal")) {

			String className = javaClass.getName();

			if (implementedClassNames.contains(implementedClassName) &&
				!className.startsWith("Base")) {

				addMessage(
					fileName,
					StringBundler.concat(
						"Class implementing '", implementedClassName,
						"' should be in 'internal' package"));
			}

			return;
		}

		if (packageName.endsWith(expectedPackageName)) {
			return;
		}

		if (!implementedClassNames.contains(implementedClassName)) {
			List extendedClassNames = javaClass.getExtendedClassNames();

			if (!extendedClassNames.contains("Base" + implementedClassName)) {
				return;
			}
		}

		BNDSettings bndSettings = getBNDSettings(fileName);

		if (bndSettings == null) {
			return;
		}

		String bundleSymbolicName = BNDSourceUtil.getDefinitionValue(
			bndSettings.getContent(), "Bundle-SymbolicName");

		Matcher matcher = _apiOrServiceBundleSymbolicNamePattern.matcher(
			bundleSymbolicName);

		bundleSymbolicName = matcher.replaceAll(StringPool.BLANK);

		if (bundleSymbolicName.endsWith(expectedPackageName)) {
			return;
		}

		int x = -1;

		while (true) {
			x = expectedPackageName.indexOf(".", x + 1);

			if (x == -1) {
				break;
			}

			if (bundleSymbolicName.endsWith(
					expectedPackageName.substring(0, x))) {

				expectedPackageName = expectedPackageName.substring(x + 1);

				break;
			}
		}

		if (packageName.endsWith(expectedPackageName)) {
			return;
		}

		if (implementedClassNames.contains(implementedClassName)) {
			addMessage(
				fileName,
				StringBundler.concat(
					"Package for class implementing '", implementedClassName,
					"' should end with '", expectedPackageName, "'"));
		}
		else {
			addMessage(
				fileName,
				StringBundler.concat(
					"Package for class extending 'Base", implementedClassName,
					"' should end with '", expectedPackageName, "'"));
		}
	}

	private void _checkModulePackageName(String fileName, String packageName)
		throws IOException {

		if (!packageName.startsWith("com.liferay")) {
			return;
		}

		BNDSettings bndSettings = getBNDSettings(fileName);

		if (bndSettings == null) {
			return;
		}

		String bundleSymbolicName = BNDSourceUtil.getDefinitionValue(
			bndSettings.getContent(), "Bundle-SymbolicName");

		if (!bundleSymbolicName.startsWith("com.liferay")) {
			return;
		}

		bundleSymbolicName = bundleSymbolicName.replaceAll(
			"\\.(api|service|test)$", StringPool.BLANK);

		if (packageName.contains(bundleSymbolicName)) {
			return;
		}

		bundleSymbolicName = bundleSymbolicName.replaceAll(
			"\\.impl$", ".internal");

		if (!packageName.contains(bundleSymbolicName)) {
			addMessage(
				fileName,
				"Package should follow Bundle-SymbolicName specified in " +
					bndSettings.getFileName());
		}
	}

	private void _checkPackageName(
		String fileName, String absolutePath, String packageName,
		String className) {

		int pos = fileName.lastIndexOf(CharPool.SLASH);

		String filePath = StringUtil.replace(
			fileName.substring(0, pos), CharPool.SLASH, CharPool.PERIOD);

		if (!filePath.endsWith(packageName)) {
			addMessage(
				fileName,
				"The declared package '" + packageName +
					"' does not match the expected package");

			return;
		}

		if (packageName.matches(".*\\.impl\\.([\\w.]+\\.)?internal") ||
			packageName.matches(".*\\.internal\\.([\\w.]+\\.)?impl")) {

			addMessage(
				fileName,
				"Do not use both 'impl' and 'internal' in the package");
		}

		List allowedInternalPackageDirNames = getAttributeValues(
			_ALLOWED_INTERNAL_PACKAGE_DIR_NAMES_KEY, absolutePath);

		for (String allowedInternalPackageDirName :
				allowedInternalPackageDirNames) {

			if (absolutePath.contains(allowedInternalPackageDirName)) {
				return;
			}
		}

		if (absolutePath.contains("-api/src/")) {
			Matcher matcher = _internalPackagePattern.matcher(packageName);

			if (matcher.find()) {
				addMessage(
					fileName,
					"Do not use '" + matcher.group(1) +
						"' package in API module");
			}

			if (packageName.contains(".api.") || packageName.endsWith(".api")) {
				addMessage(
					fileName,
					"Do not use 'api' in the package for classes in the API " +
						"module");
			}
		}

		if (className.matches(".*(? expectedPackagePathDataEntries = getAttributeValues(
			_EXPECTED_PACKAGE_PATH_DATA_KEY, absolutePath);

		for (String expectedPackagePathDataEntry :
				expectedPackagePathDataEntries) {

			String[] array = StringUtil.split(
				expectedPackagePathDataEntry, CharPool.COLON);

			String expectedPackagePath = array[1];

			if ((array.length == 2) && className.matches(array[0]) &&
				!packageName.endsWith("." + expectedPackagePath) &&
				!packageName.contains("." + expectedPackagePath + ".")) {

				addMessage(
					fileName,
					StringBundler.concat(
						"Class '", className,
						"' should be in package ending with '.", array[1],
						"'"));
			}
		}
	}

	private static final String _ALLOWED_INTERNAL_PACKAGE_DIR_NAMES_KEY =
		"allowedInternalPackageDirNames";

	private static final String _EXPECTED_INTERNAL_IMPLEMENTS_DATA_KEY =
		"expectedInternalImplementsData";

	private static final String _EXPECTED_PACKAGE_PATH_DATA_KEY =
		"expectedPackagePathData";

	private static final Pattern _apiOrServiceBundleSymbolicNamePattern =
		Pattern.compile("\\.(api|service)$");
	private static final Pattern _internalPackagePattern = Pattern.compile(
		"\\.(impl|internal)(\\.|\\Z)");

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy