com.alibaba.p3c.pmd.lang.java.rule.concurrent.ThreadShouldSetNameRule Maven / Gradle / Ivy
/*
* Copyright 1999-2017 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.p3c.pmd.lang.java.rule.concurrent;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
/**
* [Mandatory] A meaningful thread name is helpful to trace the error information,
* so assign a name when creating threads or thread pools.
*
* Detection rule //TODO should review
* 1. Use specific constructor while create thread pool
* 2. Use Executors.defaultThreadFactory() is not allowed
*
* @author caikang
* @date 2016/11/16
* @see AvoidManuallyCreateThreadRule
*/
public class ThreadShouldSetNameRule extends AbstractAliRule {
private static final int ARGUMENT_LENGTH_2 = 2;
private static final int ARGUMENT_LENGTH_6 = 6;
private static final int INDEX_1 = 1;
private static final int SINGLE_LENGTH = 1;
private static final String MESSAGE_KEY_PREFIX = "java.concurrent.ThreadShouldSetNameRule.violation.msg";
@Override
public Object visit(ASTAllocationExpression node, Object data) {
//Custom Class
if (node.getType() == null) {
return super.visit(node, data);
}
if (!ExecutorService.class.isAssignableFrom(node.getType())) {
return super.visit(node, data);
}
if (ThreadPoolExecutor.class == node.getType()) {
return checkThreadPoolExecutor(node, data);
}
if (ScheduledThreadPoolExecutor.class == node.getType()) {
return checkSchedulePoolExecutor(node, data);
}
return super.visit(node, data);
}
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
return super.visit(node, data);
}
private Object checkThreadPoolExecutor(ASTAllocationExpression node, Object data) {
ASTArgumentList argumentList = node.getFirstDescendantOfType(ASTArgumentList.class);
if (argumentList.jjtGetNumChildren() < ARGUMENT_LENGTH_6
|| !checkThreadFactoryArgument((ASTExpression)argumentList.jjtGetChild(ARGUMENT_LENGTH_6 - INDEX_1))) {
addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + ".ThreadPoolExecutor");
}
return super.visit(node, data);
}
private Object checkSchedulePoolExecutor(ASTAllocationExpression node, Object data) {
ASTArgumentList argumentList = node.getFirstDescendantOfType(ASTArgumentList.class);
if (argumentList.jjtGetNumChildren() < ARGUMENT_LENGTH_2
|| !checkThreadFactoryArgument((ASTExpression)argumentList.jjtGetChild(ARGUMENT_LENGTH_2 - INDEX_1))) {
addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + ".ScheduledThreadPoolExecutor");
}
return super.visit(node, data);
}
private boolean checkThreadFactoryArgument(ASTExpression expression) {
if (expression.getType() != null && ThreadFactory.class.isAssignableFrom(expression.getType())) {
return true;
}
ASTName name = expression.getFirstDescendantOfType(ASTName.class);
if (name != null && name.getType() == Executors.class) {
return false;
}
ASTLambdaExpression lambdaExpression = expression.getFirstDescendantOfType(ASTLambdaExpression.class);
if (lambdaExpression != null) {
List variableDeclaratorIds =
lambdaExpression.findChildrenOfType(ASTVariableDeclaratorId.class);
if (variableDeclaratorIds == null || variableDeclaratorIds.size() != SINGLE_LENGTH) {
return false;
}
} else if (expression.getType() != null
&& RejectedExecutionHandler.class.isAssignableFrom(expression.getType())) {
return false;
}
return true;
}
}