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

com.liferay.source.formatter.checkstyle.check.MVCCommandNameCheck Maven / Gradle / Ivy

The newest version!
/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

package com.liferay.source.formatter.checkstyle.check;

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.TextFormatter;

import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FullIdent;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil;

import java.io.File;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Hugo Huijser
 */
public class MVCCommandNameCheck extends BaseCheck {

	@Override
	public int[] getDefaultTokens() {
		return new int[] {TokenTypes.CLASS_DEF};
	}

	@Override
	protected void doVisitToken(DetailAST detailAST) {
		if ((detailAST.getParent() != null) ||
			AnnotationUtil.containsAnnotation(detailAST, "Deprecated")) {

			return;
		}

		String className = getName(detailAST);

		if (!className.endsWith("MVCActionCommand") &&
			!className.endsWith("MVCRenderCommand") &&
			!className.endsWith("MVCResourceCommand")) {

			return;
		}

		String absolutePath = getAbsolutePath();

		int pos = absolutePath.lastIndexOf("-web/");

		if (pos == -1) {
			return;
		}

		DetailAST annotationDetailAST = AnnotationUtil.getAnnotation(
			detailAST, "Component");

		if (annotationDetailAST == null) {
			return;
		}

		DetailAST propertyAnnotationMemberValuePairDetailAST =
			getAnnotationMemberValuePairDetailAST(
				annotationDetailAST, "property");

		if (propertyAnnotationMemberValuePairDetailAST == null) {
			return;
		}

		DetailAST annotationArrayInitDetailAST =
			propertyAnnotationMemberValuePairDetailAST.findFirstToken(
				TokenTypes.ANNOTATION_ARRAY_INIT);

		if (annotationArrayInitDetailAST == null) {
			return;
		}

		Map mvcCommandNamesMap = _getMVCCommandNamesMap(
			annotationArrayInitDetailAST);

		if (mvcCommandNamesMap.isEmpty()) {
			return;
		}

		String modulePath = absolutePath.substring(0, pos);

		boolean validateActionName = false;

		if (mvcCommandNamesMap.size() == 1) {
			validateActionName = true;
		}

		for (Map.Entry entry : mvcCommandNamesMap.entrySet()) {
			String mvcCommandName = entry.getKey();

			if (!_hasValidMVCCommandName(
					mvcCommandName, detailAST, annotationArrayInitDetailAST,
					className, modulePath, validateActionName)) {

				log(entry.getValue(), _MSG_INCORRECT_VALUE, mvcCommandName);
			}
		}
	}

	private String _getExpectedActionName(String className) {
		String name = StringUtil.removeSubstrings(
			className, "MVCActionCommand", "MVCRenderCommand",
			"MVCResourceCommand");

		name = StringUtil.replace(
			name, new String[] {"OAuth", "WebDAV", "WeDeploy"},
			new String[] {"Oauth", "Webdav", "Wedeploy"});

		Matcher matcher = _classNamePattern.matcher(className);

		while (matcher.find()) {
			String match = matcher.group(1);

			name = StringUtil.replaceFirst(
				name, match, StringUtil.lowerCase(match), matcher.start(1));
		}

		name = StringUtil.replace(
			TextFormatter.format(name, TextFormatter.K), CharPool.DASH,
			CharPool.UNDERLINE);

		return StringUtil.replace(name, "mfafido2", "mfa_fido2");
	}

	private Map _getMVCCommandNamesMap(
		DetailAST annotationArrayInitDetailAST) {

		Map mvcCommandNamesMap = new HashMap<>();

		List expressionDetailASTList = getAllChildTokens(
			annotationArrayInitDetailAST, false, TokenTypes.EXPR);

		for (DetailAST expressionDetailAST : expressionDetailASTList) {
			DetailAST firstChildDetailAST = expressionDetailAST.getFirstChild();

			if (firstChildDetailAST.getType() != TokenTypes.STRING_LITERAL) {
				continue;
			}

			String value = firstChildDetailAST.getText();

			if (value.startsWith("\"mvc.command.name=") &&
				!value.equals("\"mvc.command.name=/\"")) {

				mvcCommandNamesMap.put(
					value.substring(18, value.length() - 1),
					expressionDetailAST.getLineNo());
			}
		}

		return mvcCommandNamesMap;
	}

	private String _getTrimmedPath(
		String[] pathArray, int abbreviatePathCount) {

		StringBundler sb = new StringBundler(pathArray.length);

		for (int i = 0; i < pathArray.length; i++) {
			String s = pathArray[i];

			if (i < abbreviatePathCount) {
				sb.append(s.charAt(0));
			}
			else {
				sb.append(s);
			}
		}

		return sb.toString();
	}

	private boolean _hasValidActionName(
		String actionName, String path, String className) {

		if (actionName.equals(_getExpectedActionName(className))) {
			return true;
		}

		String[] pathArray = StringUtil.split(path, CharPool.UNDERLINE);

		for (int i = 0; i < pathArray.length; i++) {
			String trimmedPath = _getTrimmedPath(pathArray, i);

			if (StringUtil.startsWith(className, trimmedPath) &&
				actionName.equals(
					_getExpectedActionName(
						className.substring(trimmedPath.length())))) {

				return true;
			}
		}

		return false;
	}

	private boolean _hasValidMVCCommandName(
		String mvcCommandName, DetailAST classDefinitionDetailAST,
		DetailAST annotationArrayInitDetailAST, String className,
		String modulePath, boolean validateActionName) {

		if (!mvcCommandName.startsWith(StringPool.SLASH) &&
			!mvcCommandName.startsWith(StringPool.TILDE)) {

			return false;
		}

		char delimiter = mvcCommandName.charAt(0);

		String[] parts = StringUtil.split(
			mvcCommandName.substring(1), delimiter);

		if (parts.length != 2) {
			return false;
		}

		String actionName = parts[1];
		String path = parts[0];

		if ((!validateActionName ||
			 _hasValidActionName(actionName, path, className)) &&
			_hasValidPath(
				path, annotationArrayInitDetailAST, delimiter, modulePath)) {

			return true;
		}

		List annotationDetailASTList = getAllChildTokens(
			classDefinitionDetailAST, true, TokenTypes.ANNOTATION);

		for (DetailAST annotationDetailAST : annotationDetailASTList) {
			if (!Objects.equals(getName(annotationDetailAST), "Reference")) {
				continue;
			}

			DetailAST targetAnnotationMemberValuePairDetailAST =
				getAnnotationMemberValuePairDetailAST(
					annotationDetailAST, "target");

			if (targetAnnotationMemberValuePairDetailAST == null) {
				continue;
			}

			FullIdent fullIdent = FullIdent.createFullIdentBelow(
				targetAnnotationMemberValuePairDetailAST.getLastChild());

			Matcher matcher = _componentNamePattern.matcher(
				fullIdent.getText());

			if (matcher.find()) {
				String expectedPath = StringUtil.replace(
					matcher.group(1), CharPool.PERIOD, CharPool.UNDERLINE);

				if (path.equals(expectedPath) &&
					actionName.equals(
						_getExpectedActionName(matcher.group(2)))) {

					return true;
				}
			}
		}

		return false;
	}

	private boolean _hasValidPath(
		String path, DetailAST annotationArrayInitDetailAST, char delimiter,
		String modulePath) {

		String moduleName = modulePath.substring(
			modulePath.lastIndexOf(delimiter) + 1);

		if (path.equals(StringUtil.replace(moduleName, '-', '_'))) {
			return true;
		}

		List stringLiteralDetailASTList = getAllChildTokens(
			annotationArrayInitDetailAST, true, TokenTypes.STRING_LITERAL);

		for (DetailAST stringLiteralDetailAST : stringLiteralDetailASTList) {
			if (!Objects.equals(
					stringLiteralDetailAST.getText(),
					"\"javax.portlet.name=\"")) {

				continue;
			}

			for (String name :
					getNames(stringLiteralDetailAST.getParent(), true)) {

				if (StringUtil.equalsIgnoreCase(path, name)) {
					return true;
				}
			}
		}

		File file = new File(
			modulePath + "-web/src/main/resources/META-INF/resources/" + path);

		return file.exists();
	}

	private static final String _MSG_INCORRECT_VALUE = "value.incorrect";

	private static final Pattern _classNamePattern = Pattern.compile(
		"[A-Z]([A-Z]+)s([A-Z]|\\Z)");
	private static final Pattern _componentNamePattern = Pattern.compile(
		"^\"\\(component\\.name=com\\.liferay\\.(.*)\\.web\\.internal" +
			"\\..*\\.(\\w+MVC\\w+Command)\\)\"$");

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy