From d79015f0743d21c67b54efd02c4418cc9bdcac3a Mon Sep 17 00:00:00 2001 From: Godin Date: Thu, 21 Oct 2010 08:19:55 +0000 Subject: [PATCH] SONAR-1832: Create an architecture rule engine --- .../bytecode/check/ArchitectureCheck.java | 98 ++++++++++++++++++ .../java/bytecode/check/BytecodeChecks.java | 3 +- .../bytecode/check/ArchitectureCheckTest.java | 89 ++++++++++++++++ .../bin/ArchitectureCheckDateForbidden.class | Bin 0 -> 648 bytes .../ArchitectureCheckOneErrorMessage.class | Bin 0 -> 444 bytes .../bin/ArchitectureCheckToSqlFromUI.class | Bin 0 -> 846 bytes .../bytecode/architecture/pom.xml | 23 ++++ .../src/ArchitectureCheckDateForbidden.java | 11 ++ .../src/ArchitectureCheckOneErrorMessage.java | 8 ++ .../src/ArchitectureCheckToSqlFromUI.java | 21 ++++ 10 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java create mode 100644 plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckDateForbidden.class create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckOneErrorMessage.class create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckToSqlFromUI.class create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/pom.xml create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckDateForbidden.java create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckOneErrorMessage.java create mode 100644 plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckToSqlFromUI.java 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 = "

Links between classes must respect defined architecture rules.

") +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 new file mode 100644 index 0000000000000000000000000000000000000000..8bd45accfc09e958987100469c6d309a13a15ee3 GIT binary patch literal 648 zcmaJ;$xZ@66s%?&96=Nj7hG@$BofaWqhd@Xs0Yx*V>8o%#&HNk<9~Spqlq8jM;Tv_ z81=#&UZ-Bw)Z0EjU*7>7plHIxl7UQ^AP|h7m5A+AV?%g#-f$?BtadE!+;LB8JW7UCOZFJD)l<)ENhK`R_e8lR ztcP>1#6`zzNZS_fA%kI4qSke^b(=r&Qm^Zjw1~K<=5CcFa{8O>6Zm06NZi)s7tq}xNA|%>0JKLd_O9^9g@}kF_Zr!qXkX^ s5{MF>K!$u1#1$w@KA6S~y$NzpVwS3;5kU%bS6ot=i)27DQ*7#GGDhO>sgX^jwMOV=ZmAanBA)T5gGMR|4q_LwTu+Z3oMMqq%qzF6ywkV!w1Ywp?tZL)cwL6WRsu$0CXR(R9wm2%R#@jf#CO zBl+y#2xFv92zHn*9?M>b-QW)#8?BOP(EEx0g9Gfr;y*18@o-tz2D{VJ1FQX4kXLy_ i_3nk^3RYN~sIt}=t;1o&VdpZy&v{(F32UqsG`|6>+HBJR literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..03cfe2219d7766c0cf597015dc834e004cf1a9ec GIT binary patch literal 846 zcmaJ<-A)rh7(LV0E-hPH3W#W1EsFF9XuPg5F^wc94F(sv->#E(VY^GGvj$(m7xCH) zHF)6z_)x|(71{NMZ1$V)f6jO2`}O^m7K?c7FZvixgXr#d=~WHE?kb(eSxAEg`xDcAB6%NNzUNL&7}NuKlJqrfp#m& zaI~xCREE0$*B7|qxaVl)hvR8^0gHu=e#=drD z2~1!!)&6++>e7=J1{opb^u(VFG=?vgH}N$Q$4U++(mOwioLO+FqUpQW%qz_Q!TN9H z1gwCio+8aWwpqF8zI&^K6{w_SH&s%@-b*Fwui8yy=qN;bOKvr)t{8NDIh zNzG$pAG-pz+nNhh5^!%uXPj6d+cL~nlcveArLok>qmjy1J0UX(kRn@NN-x&(IF{<8 zKYdM6I@kBJ#*g}m + 4.0.0 + org.codehaus.sonar + 0.1-SNAPSHOT + sonar-bytecode + jar + + + src + bin + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + + 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(); + } + } +} -- 2.39.5