summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorGodin <mandrikov@gmail.com>2010-10-21 08:19:55 +0000
committerGodin <mandrikov@gmail.com>2010-10-21 08:19:55 +0000
commitd79015f0743d21c67b54efd02c4418cc9bdcac3a (patch)
tree90a381e9e1a9416437d1a502924a3317d75e15ed /plugins
parent417217bca95368825bc4ffa6244e90b18ed41286 (diff)
downloadsonarqube-d79015f0743d21c67b54efd02c4418cc9bdcac3a.tar.gz
sonarqube-d79015f0743d21c67b54efd02c4418cc9bdcac3a.zip
SONAR-1832: Create an architecture rule engine
Diffstat (limited to 'plugins')
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/ArchitectureCheck.java98
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/java/org/sonar/java/bytecode/check/BytecodeChecks.java3
-rw-r--r--plugins/sonar-squid-java-plugin/src/test/java/org/sonar/java/bytecode/check/ArchitectureCheckTest.java89
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckDateForbidden.classbin0 -> 648 bytes
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckOneErrorMessage.classbin0 -> 444 bytes
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckToSqlFromUI.classbin0 -> 846 bytes
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/pom.xml23
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckDateForbidden.java11
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckOneErrorMessage.java8
-rw-r--r--plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/src/ArchitectureCheckToSqlFromUI.java21
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
new file mode 100644
index 00000000000..8bd45accfc0
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckDateForbidden.class
Binary files differ
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
new file mode 100644
index 00000000000..ca6d35538d7
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckOneErrorMessage.class
Binary files differ
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 00000000000..03cfe2219d7
--- /dev/null
+++ b/plugins/sonar-squid-java-plugin/test-resources/bytecode/architecture/bin/ArchitectureCheckToSqlFromUI.class
Binary files differ
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();
+ }
+ }
+}