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

com.liferay.source.formatter.checkstyle.check.SystemEventCheck 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.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.source.formatter.check.util.SourceUtil;

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.List;
import java.util.Objects;

import org.dom4j.Document;
import org.dom4j.Element;

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

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

	@Override
	protected void doVisitToken(DetailAST detailAST) {
		_entityElement = null;

		DetailAST parentDetailAST = detailAST.getParent();

		if (parentDetailAST != null) {
			return;
		}

		if (detailAST.getType() == TokenTypes.CLASS_DEF) {
			_checkSystemEventConstants(detailAST);
		}
	}

	private void _checkSystemEventConstants(DetailAST detailAST) {
		if (AnnotationUtil.containsAnnotation(detailAST, "Deprecated")) {
			return;
		}

		String className = getName(detailAST);

		if (!className.endsWith("LocalServiceImpl")) {
			return;
		}

		String entityName = StringUtil.removeSubstring(
			className, "LocalServiceImpl");

		DetailAST objBlockDetailAST = detailAST.findFirstToken(
			TokenTypes.OBJBLOCK);

		List methodDefDetailASTList = getAllChildTokens(
			objBlockDetailAST, false, TokenTypes.METHOD_DEF);

		for (DetailAST methodDefDetailAST : methodDefDetailASTList) {
			DetailAST modifiersDetailAST = methodDefDetailAST.findFirstToken(
				TokenTypes.MODIFIERS);

			if (!modifiersDetailAST.branchContains(TokenTypes.LITERAL_PUBLIC) ||
				AnnotationUtil.containsAnnotation(
					methodDefDetailAST, "Deprecated")) {

				continue;
			}

			String methodName = getName(methodDefDetailAST);

			if (_hasSystemDeleteEventAnnotation(methodDefDetailAST)) {
				if (!entityName.equals(
						_getFirstParameterTypeName(methodDefDetailAST))) {

					log(
						methodDefDetailAST, _MSG_UNNEEDED_SYSTEM_EVENT_1,
						methodName, entityName);
				}

				Element entityElement = _getEntityElement(entityName);

				if (entityElement == null) {
					return;
				}

				if (!_implementsClassedModel(entityElement)) {
					log(
						methodDefDetailAST, _MSG_UNNEEDED_SYSTEM_EVENT_2,
						methodName, entityName);
				}

				continue;
			}

			if (!methodName.startsWith("delete") ||
				!_hasDeleteFromPersistence(
					methodDefDetailASTList, methodDefDetailAST, entityName,
					methodName) ||
				!entityName.equals(
					_getFirstParameterTypeName(methodDefDetailAST))) {

				continue;
			}

			Element entityElement = _getEntityElement(entityName);

			if (entityElement == null) {
				return;
			}

			if (_implementsClassedModel(entityElement)) {
				log(methodDefDetailAST, _MSG_MISSING_SYSTEM_EVENT, methodName);
			}
		}
	}

	private DetailAST _getCalledMethodDefDetailAST(
		DetailAST methodDefDetailAST, String methodName,
		List methodDefDetailASTList) {

		DetailAST matchingMethodDefDetailAST = null;

		for (DetailAST curMethodDefDetailAST : methodDefDetailASTList) {
			if (methodDefDetailAST.getLineNo() ==
					curMethodDefDetailAST.getLineNo()) {

				continue;
			}

			DetailAST identDetailAST = curMethodDefDetailAST.findFirstToken(
				TokenTypes.IDENT);

			if (!methodName.equals(identDetailAST.getText())) {
				continue;
			}

			DetailAST parametersDetailAST =
				curMethodDefDetailAST.findFirstToken(TokenTypes.PARAMETERS);

			List parameterDefDetailASTList = getAllChildTokens(
				parametersDetailAST, false, TokenTypes.PARAMETER_DEF);

			if (parameterDefDetailASTList.size() != 1) {
				continue;
			}

			if (matchingMethodDefDetailAST == null) {
				matchingMethodDefDetailAST = curMethodDefDetailAST;
			}
			else {
				return null;
			}
		}

		return matchingMethodDefDetailAST;
	}

	private Element _getEntityElement(String entityName) {
		if (_entityElement != null) {
			return _entityElement;
		}

		String absolutePath = getAbsolutePath();

		File serviceXMLFile = null;

		int pos = absolutePath.length();

		while (true) {
			pos = absolutePath.lastIndexOf("/", pos - 1);

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

			serviceXMLFile = new File(
				absolutePath.substring(0, pos + 1) + "service.xml");

			if (serviceXMLFile.exists()) {
				break;
			}
		}

		Document document = SourceUtil.readXML(serviceXMLFile);

		if (document == null) {
			return null;
		}

		Element rootElement = document.getRootElement();

		for (Element entityElement :
				(List)rootElement.elements("entity")) {

			if (entityName.equals(entityElement.attributeValue("name"))) {
				_entityElement = entityElement;

				return _entityElement;
			}
		}

		return null;
	}

	private String _getFirstParameterTypeName(DetailAST methodDefDetailAST) {
		DetailAST parametersDetailAST = methodDefDetailAST.findFirstToken(
			TokenTypes.PARAMETERS);

		List parameterDefDetailASTList = getAllChildTokens(
			parametersDetailAST, false, TokenTypes.PARAMETER_DEF);

		if (parameterDefDetailASTList.isEmpty()) {
			return null;
		}

		DetailAST firstParameterDefDetailAST = parameterDefDetailASTList.get(0);

		DetailAST typeDetailAST = firstParameterDefDetailAST.findFirstToken(
			TokenTypes.TYPE);

		DetailAST firstChildDetailAST = typeDetailAST.getFirstChild();

		if (firstChildDetailAST.getType() == TokenTypes.IDENT) {
			return firstChildDetailAST.getText();
		}

		return null;
	}

	private String _getPrimaryKeyType(Element entityElement) {
		for (Element columnElement :
				(List)entityElement.elements("column")) {

			if (GetterUtil.getBoolean(
					columnElement.attributeValue("primary"))) {

				return columnElement.attributeValue("type");
			}
		}

		return null;
	}

	/*
	private boolean _requiresSystemDeleteEventAnnotation(
		DetailAST methodDefDetailAST, String entityName,
		Element entityElement) {

		if (!entityName.equals(
				_getFirstParameterTypeName(methodDefDetailAST))) {

			return false;
		}

		String primaryKeyType = _getPrimaryKeyType(entityElement);

		if (Validator.isNull(primaryKeyType) ||
			!primaryKeyType.equals("long") ||
			!_hasColumn(entityElement, "companyId") ||
			!_hasColumn(entityElement, "createDate") ||
			!_hasColumn(entityElement, "modifiedDate") ||
			!_hasColumn(entityElement, "userId") ||
			!_hasColumn(entityElement, "userName")) {

			return false;
		}

		return true;
	}

	*/

	private boolean _hasColumn(Element entityElement, String name) {
		for (Element columnElement :
				(List)entityElement.elements("column")) {

			if (name.equals(columnElement.attributeValue("name"))) {
				return true;
			}
		}

		return false;
	}

	private boolean _hasDeleteFromPersistence(
		List methodDefDetailASTList, DetailAST methodDefDetailAST,
		String entityName, String methodName) {

		if (methodDefDetailAST == null) {
			return false;
		}

		List methodCallDetailASTList = getAllChildTokens(
			methodDefDetailAST, true, TokenTypes.METHOD_CALL);

		for (DetailAST methodCallDetailAST : methodCallDetailASTList) {
			DetailAST firstChildDetailAST = methodCallDetailAST.getFirstChild();

			if (firstChildDetailAST.getType() == TokenTypes.DOT) {
				FullIdent fullIdent = FullIdent.createFullIdent(
					firstChildDetailAST);

				String methodCall = fullIdent.getText();

				if (methodCall.matches(
						"(?i)" + entityName + "Persistence\\.remove.*") ||
					methodCall.equals("super." + methodName)) {

					return true;
				}
			}
			else if ((firstChildDetailAST.getType() == TokenTypes.IDENT) &&
					 methodName.equals(firstChildDetailAST.getText())) {

				DetailAST elistDetailAST = methodCallDetailAST.findFirstToken(
					TokenTypes.ELIST);

				List exprDetailASTList = getAllChildTokens(
					elistDetailAST, false, TokenTypes.EXPR);

				if (exprDetailASTList.size() == 1) {
					DetailAST calledMethodDefDetailAST =
						_getCalledMethodDefDetailAST(
							methodDefDetailAST, methodName,
							methodDefDetailASTList);

					if (_hasDeleteFromPersistence(
							methodDefDetailASTList, calledMethodDefDetailAST,
							methodName, entityName)) {

						return true;
					}
				}
			}
		}

		return false;
	}

	private boolean _hasSystemDeleteEventAnnotation(
		DetailAST methodDefDetailAST) {

		DetailAST annotationDetailAST = AnnotationUtil.getAnnotation(
			methodDefDetailAST, "SystemEvent");

		if (annotationDetailAST == null) {
			return false;
		}

		List annotationMemberValuePairDetailASTList =
			getAllChildTokens(
				annotationDetailAST, false,
				TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR);

		for (DetailAST annotationMemberValuePairDetailAST :
				annotationMemberValuePairDetailASTList) {

			DetailAST identDetailAST =
				annotationMemberValuePairDetailAST.findFirstToken(
					TokenTypes.IDENT);

			if (!Objects.equals(identDetailAST.getText(), "type")) {
				continue;
			}

			DetailAST exprDetailAST =
				annotationMemberValuePairDetailAST.findFirstToken(
					TokenTypes.EXPR);

			FullIdent fullIdent = FullIdent.createFullIdentBelow(exprDetailAST);

			if (Objects.equals(
					fullIdent.getText(), "SystemEventConstants.TYPE_DELETE")) {

				return true;
			}
		}

		return false;
	}

	private boolean _implementsClassedModel(Element entityElement) {
		String primaryKeyType = _getPrimaryKeyType(entityElement);

		if (Validator.isNull(primaryKeyType) ||
			!primaryKeyType.equals("long") ||
			!_hasColumn(entityElement, "companyId") ||
			!_hasColumn(entityElement, "createDate") ||
			!_hasColumn(entityElement, "modifiedDate") ||
			!_hasColumn(entityElement, "userId") ||
			!_hasColumn(entityElement, "userName")) {

			return false;
		}

		return true;
	}

	private static final String _MSG_MISSING_SYSTEM_EVENT =
		"system.event.missing";

	private static final String _MSG_UNNEEDED_SYSTEM_EVENT_1 =
		"system.event.unneeded.1";

	private static final String _MSG_UNNEEDED_SYSTEM_EVENT_2 =
		"system.event.unneeded.2";

	private Element _entityElement;

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy