diff options
author | Godin <mandrikov@gmail.com> | 2010-10-21 08:19:55 +0000 |
---|---|---|
committer | Godin <mandrikov@gmail.com> | 2010-10-21 08:19:55 +0000 |
commit | d79015f0743d21c67b54efd02c4418cc9bdcac3a (patch) | |
tree | 90a381e9e1a9416437d1a502924a3317d75e15ed /plugins | |
parent | 417217bca95368825bc4ffa6244e90b18ed41286 (diff) | |
download | sonarqube-d79015f0743d21c67b54efd02c4418cc9bdcac3a.tar.gz sonarqube-d79015f0743d21c67b54efd02c4418cc9bdcac3a.zip |
SONAR-1832: Create an architecture rule engine
Diffstat (limited to 'plugins')
10 files changed, 252 insertions, 1 deletions
diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java new file mode 100644 index 00000000000..e51d241ce87 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java @@ -0,0 +1,98 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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 3 of the License, or (at your option) any later version. + * + * Sonar 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.java.bytecode.check; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.WildcardPattern; +import org.sonar.check.Check; +import org.sonar.check.CheckProperty; +import org.sonar.check.IsoCategory; +import org.sonar.check.Priority; +import org.sonar.java.bytecode.asm.AsmClass; +import org.sonar.java.bytecode.asm.AsmEdge; +import org.sonar.squid.api.CheckMessage; +import org.sonar.squid.api.SourceCodeEdgeUsage; +import org.sonar.squid.api.SourceFile; + +@Check(key = "Dependency", title = "Respect rule architecture", isoCategory = IsoCategory.Portability, priority = Priority.MINOR, description = "<p>Links between classes must respect defined architecture rules.</p>") +public class ArchitectureCheck extends BytecodeCheck { + + @CheckProperty(title = "Pattern forbidden for from classes", key = "fromClasses") + private String fromClasses = new String(); + + @CheckProperty(title = "Pattern forbidden for to classes", key = "toClasses") + private String toClasses = new String(); + + public String getFromClasses() { + return fromClasses; + } + + public void setFromClasses(String fromClasses) { + this.fromClasses = fromClasses; + } + + public String getToClasses() { + return toClasses; + } + + public void setToClasses(String toClasses) { + this.toClasses = toClasses; + } + + private AsmClass asmClass; + + @Override + public void visitClass(AsmClass asmClass) { + this.asmClass = asmClass; + } + + @Override + public void visitEdge(AsmEdge edge) { + if (edge != null) { + SourceCodeEdgeUsage usage = edge.getUsage(); + if (usage.equals(SourceCodeEdgeUsage.USES) || usage.equals(SourceCodeEdgeUsage.CALLS_METHOD) + || usage.equals(SourceCodeEdgeUsage.CALLS_FIELD) || usage.equals(SourceCodeEdgeUsage.CONTAINS)) { + String internalNameTargetClass = edge.getTargetAsmClass().getInternalName(); + String nameAsmClass = asmClass.getInternalName(); + if (matchesPattern(nameAsmClass, fromClasses) && matchesPattern(internalNameTargetClass, toClasses)) { + SourceFile sourceFile = getSourceFile(asmClass); + CheckMessage message = new CheckMessage(this, nameAsmClass + " shouldn't directly use " + internalNameTargetClass); + message.setLine(edge.getSourceLineNumber()); + sourceFile.log(message); + } + } + } + } + + private boolean matchesPattern(String className, String pattern) { + if (StringUtils.isEmpty(pattern)) { + return true; + } + String[] patterns = pattern.split(","); + for (String p : patterns) { + p = StringUtils.replace(p, ".", "/"); + if (WildcardPattern.create(p).match(className)) { + return true; + } + } + return false; + } + +} diff --git a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/BytecodeChecks.java b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/BytecodeChecks.java index 67e265258d9..96b921f9769 100644 --- a/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/BytecodeChecks.java +++ b/plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/BytecodeChecks.java @@ -31,6 +31,7 @@ public final class BytecodeChecks { return Arrays.asList( (Class) CallToDeprecatedMethodCheck.class, UnusedPrivateMethodCheck.class, - UnusedProtectedMethodCheck.class); + UnusedProtectedMethodCheck.class, + ArchitectureCheck.class); } } diff --git a/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java new file mode 100644 index 00000000000..f56e2843a60 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java @@ -0,0 +1,89 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2009 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * Sonar 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 3 of the License, or (at your option) any later version. + * + * Sonar 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.java.bytecode.check; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.sonar.java.ast.SquidTestUtils.getFile; + +import org.junit.Test; +import org.sonar.java.ast.JavaAstScanner; +import org.sonar.java.bytecode.BytecodeScanner; +import org.sonar.java.squid.JavaSquidConfiguration; +import org.sonar.squid.Squid; +import org.sonar.squid.api.CheckMessage; +import org.sonar.squid.api.SourceFile; + +public class ArchitectureCheckTest { + + private Squid squid; + + @Test + public void testDependencyCheckOneErrorMessage() { + check("", "java.**.Pattern"); + + SourceFile file = (SourceFile) squid.search("ArchitectureCheckOneErrorMessage.java"); + assertThat(file.getCheckMessages().size(), is(1)); + CheckMessage message = file.getCheckMessages().iterator().next(); + assertThat(message.getDefaultMessage(), is("ArchitectureCheckOneErrorMessage shouldn't directly use java/util/regex/Pattern")); + assertThat(message.getLine(), is(6)); + } + + @Test + public void testDependencyCheckDateForbidden() { + check("", "**.Date"); + + SourceFile file = (SourceFile) squid.search("ArchitectureCheckDateForbidden.java"); + assertThat(file.getCheckMessages().size(), is(3)); + // for (CheckMessage message : file.getCheckMessages()) { + // System.out.println(message.getDefaultMessage()); + // } + } + + @Test + public void testDependencyCheckToSqlFromUI() { + check("*UI", "java.sql.*"); + + SourceFile file = (SourceFile) squid.search("ArchitectureCheckToSqlFromUI.java"); + assertThat(file.getCheckMessages().size(), is(7)); + // for (CheckMessage message : file.getCheckMessages()) { + // System.out.println(message.getDefaultMessage() + " at line " + message.getLine()); + // } + } + + @Test + public void testDependencyCheckOKFromClassesToClasses() { + check("*SA", "java.sql.*"); + + SourceFile file = (SourceFile) squid.search("ArchitectureCheckToSqlFromUI.java"); + assertThat(file.getCheckMessages().size(), is(0)); + } + + private void check(String fromClasses, String toClasses) { + ArchitectureCheck check = new ArchitectureCheck(); + check.setFromClasses(fromClasses); + check.setToClasses(toClasses); + + squid = new Squid(new JavaSquidConfiguration()); + squid.register(JavaAstScanner.class).scanDirectory(getFile("/bytecode/architecture/src")); + squid.registerVisitor(check); + squid.register(BytecodeScanner.class).scanDirectory(getFile("/bytecode/architecture/bin")); + } +} diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckDateForbidden.class b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckDateForbidden.class Binary files differnew file mode 100644 index 00000000000..8bd45accfc0 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckDateForbidden.class diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckOneErrorMessage.class b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckOneErrorMessage.class Binary files differnew file mode 100644 index 00000000000..ca6d35538d7 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckOneErrorMessage.class diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckToSqlFromUI.class b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckToSqlFromUI.class Binary files differnew file mode 100644 index 00000000000..03cfe2219d7 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckToSqlFromUI.class diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/pom.xml b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/pom.xml new file mode 100644 index 00000000000..3689efdf57a --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/pom.xml @@ -0,0 +1,23 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.codehaus.sonar</groupId> + <version>0.1-SNAPSHOT</version> + <artifactId>sonar-bytecode</artifactId> + <packaging>jar</packaging> + + <build> + <sourceDirectory>src</sourceDirectory> + <outputDirectory>bin</outputDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <target>1.5</target> + <source>1.5</source> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckDateForbidden.java b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckDateForbidden.java new file mode 100644 index 00000000000..be4c58f3e4e --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckDateForbidden.java @@ -0,0 +1,11 @@ +import java.sql.Date; +import java.util.Calendar; + +public class ArchitectureCheckDateForbidden { + + public ArchitectureCheckDateForbidden() { + Date dateSql = new Date(200000); + java.util.Date dateUtil = Calendar.getInstance().getTime(); + long time = dateUtil.getTime(); + } +} diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckOneErrorMessage.java b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckOneErrorMessage.java new file mode 100644 index 00000000000..46f02755655 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckOneErrorMessage.java @@ -0,0 +1,8 @@ +import java.util.regex.Pattern; + +public class ArchitectureCheckOneErrorMessage { + + public ArchitectureCheckOneErrorMessage() { + Pattern.compile("*.java"); + } +} diff --git a/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckToSqlFromUI.java b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckToSqlFromUI.java new file mode 100644 index 00000000000..18f58ba4801 --- /dev/null +++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckToSqlFromUI.java @@ -0,0 +1,21 @@ +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + + +public class ArchitectureCheckToSqlFromUI { + + ResultSet result; + + Connection connection; + + public ArchitectureCheckToSqlFromUI(Statement statement, String requete) { + try { + connection = statement.getConnection(); + result = statement.executeQuery(requete); + } catch (SQLException sql) { + sql.printStackTrace(); + } + } +} |