- GNU LESSER GENERAL PUBLIC LICENSE
+ GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
scp -i ~/.ssh/id_rsa-sonar-keypair -C -r docs.tar root@ec2-75-101-133-159.compute-1.amazonaws.com:/tmp
-ssh -i ~/.ssh/id_rsa-sonar-keypair root@ec2-75-101-133-159.compute-1.amazonaws.com 'tar -xf /tmp/docs.tar -C /vol/www/sonar.codehaus.org/docs'
\ No newline at end of file
+ssh -i ~/.ssh/id_rsa-sonar-keypair root@ec2-75-101-133-159.compute-1.amazonaws.com 'tar -xf /tmp/docs.tar -C /vol/www/sonar.codehaus.org/docs'
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.plugins.core.sensors;\r
-\r
-import javax.persistence.EntityManager;\r
-import javax.persistence.EntityTransaction;\r
-import javax.persistence.Query;\r
-\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-import org.sonar.api.batch.Decorator;\r
-import org.sonar.api.batch.DecoratorContext;\r
-import org.sonar.api.batch.DependedUpon;\r
-import org.sonar.api.batch.DependsUpon;\r
-import org.sonar.api.database.DatabaseSession;\r
-import org.sonar.api.database.model.Snapshot;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.batch.index.ResourcePersister;\r
-\r
-/**\r
- * Decorator that currently only closes a review when its corresponding violation has been fixed.\r
- */\r
-@DependsUpon("ViolationPersisterDecorator")\r
-public class ReviewsDecorator implements Decorator {\r
-\r
- private static final Logger LOG = LoggerFactory.getLogger(ReviewsDecorator.class);\r
-\r
- private ResourcePersister resourcePersister;\r
- private DatabaseSession databaseSession;\r
-\r
- public ReviewsDecorator(ResourcePersister resourcePersister, DatabaseSession databaseSession) {\r
- this.resourcePersister = resourcePersister;\r
- this.databaseSession = databaseSession;\r
- }\r
-\r
- public boolean shouldExecuteOnProject(Project project) {\r
- return true;\r
- }\r
-\r
- public void decorate(Resource resource, DecoratorContext context) {\r
- Snapshot currentSnapshot = resourcePersister.getSnapshot(resource);\r
- if (currentSnapshot != null) {\r
- int resourceId = currentSnapshot.getResourceId();\r
- int snapshotId = currentSnapshot.getId();\r
- Query query = databaseSession.createNativeQuery("UPDATE reviews SET status='closed' " + "WHERE resource_id = " + resourceId\r
- + " AND rule_failure_permanent_id NOT IN " + "(SELECT permanent_id FROM rule_failures WHERE snapshot_id = " + snapshotId + ")");\r
- int rowUpdated = query.executeUpdate();\r
- LOG.debug("- {} reviews set to 'closed' on resource #{}", rowUpdated, resourceId);\r
- databaseSession.commit();\r
- }\r
- }\r
-\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.plugins.core.sensors;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Query;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.batch.index.ResourcePersister;
+
+/**
+ * Decorator that currently only closes a review when its corresponding violation has been fixed.
+ */
+@DependsUpon("ViolationPersisterDecorator")
+public class ReviewsDecorator implements Decorator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ReviewsDecorator.class);
+
+ private ResourcePersister resourcePersister;
+ private DatabaseSession databaseSession;
+
+ public ReviewsDecorator(ResourcePersister resourcePersister, DatabaseSession databaseSession) {
+ this.resourcePersister = resourcePersister;
+ this.databaseSession = databaseSession;
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+
+ public void decorate(Resource resource, DecoratorContext context) {
+ Snapshot currentSnapshot = resourcePersister.getSnapshot(resource);
+ if (currentSnapshot != null) {
+ int resourceId = currentSnapshot.getResourceId();
+ int snapshotId = currentSnapshot.getId();
+ Query query = databaseSession.createNativeQuery("UPDATE reviews SET status='closed' " + "WHERE resource_id = " + resourceId
+ + " AND rule_failure_permanent_id NOT IN " + "(SELECT permanent_id FROM rule_failures WHERE snapshot_id = " + snapshotId + ")");
+ int rowUpdated = query.executeUpdate();
+ LOG.debug("- {} reviews set to 'closed' on resource #{}", rowUpdated, resourceId);
+ databaseSession.commit();
+ }
+ }
+
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.plugins.core.timemachine;\r
-\r
-import com.google.common.collect.LinkedHashMultimap;\r
-import com.google.common.collect.Lists;\r
-import com.google.common.collect.Multimap;\r
-import org.apache.commons.codec.digest.DigestUtils;\r
-import org.apache.commons.io.IOUtils;\r
-import org.apache.commons.lang.ObjectUtils;\r
-import org.apache.commons.lang.StringUtils;\r
-import org.codehaus.plexus.util.StringInputStream;\r
-import org.sonar.api.batch.*;\r
-import org.sonar.api.database.model.RuleFailureModel;\r
-import org.sonar.api.database.model.SnapshotSource;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.api.rules.Rule;\r
-import org.sonar.api.rules.RuleFinder;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.api.utils.SonarException;\r
-import org.sonar.batch.components.PastViolationsLoader;\r
-import org.sonar.batch.index.ViolationPersister;\r
-\r
-import java.io.IOException;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.List;\r
-\r
-@DependsUpon(DecoratorBarriers.END_OF_VIOLATIONS_GENERATION)\r
-@DependedUpon("ViolationPersisterDecorator") /* temporary workaround - see NewViolationsDecorator */\r
-public class ViolationPersisterDecorator implements Decorator {\r
-\r
- /**\r
- * Those chars would be ignored during generation of checksums.\r
- */\r
- private static final String SPACE_CHARS = "\t\n\r ";\r
-\r
- private RuleFinder ruleFinder;\r
- private PastViolationsLoader pastViolationsLoader;\r
- private ViolationPersister violationPersister;\r
-\r
- List<String> checksums = Lists.newArrayList();\r
-\r
- public ViolationPersisterDecorator(RuleFinder ruleFinder, PastViolationsLoader pastViolationsLoader, ViolationPersister violationPersister) {\r
- this.ruleFinder = ruleFinder;\r
- this.pastViolationsLoader = pastViolationsLoader;\r
- this.violationPersister = violationPersister;\r
- }\r
-\r
- public boolean shouldExecuteOnProject(Project project) {\r
- return true;\r
- }\r
-\r
- public void decorate(Resource resource, DecoratorContext context) {\r
- if (context.getViolations().isEmpty()) {\r
- return;\r
- }\r
- // Load past violations\r
- List<RuleFailureModel> pastViolations = pastViolationsLoader.getPastViolations(resource);\r
- // Load current source and calculate checksums\r
- checksums = getChecksums(pastViolationsLoader.getSource(resource));\r
- // Save violations\r
- compareWithPastViolations(context, pastViolations);\r
- // Clear cache\r
- checksums.clear();\r
- }\r
-\r
- private void compareWithPastViolations(DecoratorContext context, List<RuleFailureModel> pastViolations) {\r
- Multimap<Rule, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create();\r
- for (RuleFailureModel pastViolation : pastViolations) {\r
- Rule rule = ruleFinder.findById(pastViolation.getRuleId());\r
- pastViolationsByRule.put(rule, pastViolation);\r
- }\r
- // for each violation, search equivalent past violation\r
- for (Violation violation : context.getViolations()) {\r
- RuleFailureModel pastViolation = selectPastViolation(violation, pastViolationsByRule);\r
- if (pastViolation != null) {\r
- // remove violation, since would be updated and shouldn't affect other violations anymore\r
- pastViolationsByRule.remove(violation.getRule(), pastViolation);\r
- }\r
- String checksum = getChecksumForLine(checksums, violation.getLineId());\r
- violationPersister.saveViolation(context.getProject(), violation, pastViolation, checksum);\r
- }\r
- violationPersister.commit();\r
- }\r
-\r
- /**\r
- * @return checksums, never null\r
- */\r
- private List<String> getChecksums(SnapshotSource source) {\r
- return source == null || source.getData() == null ? Collections.<String>emptyList() : getChecksums(source.getData());\r
- }\r
-\r
- static List<String> getChecksums(String data) {\r
- List<String> result = Lists.newArrayList();\r
- StringInputStream stream = new StringInputStream(data);\r
- try {\r
- List<String> lines = IOUtils.readLines(stream);\r
- for (String line : lines) {\r
- result.add(getChecksum(line));\r
- }\r
- } catch (IOException e) {\r
- throw new SonarException("Unable to calculate checksums", e);\r
- \r
- } finally {\r
- IOUtils.closeQuietly(stream);\r
- }\r
- return result;\r
- }\r
-\r
- static String getChecksum(String line) {\r
- String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, "");\r
- return DigestUtils.md5Hex(reducedLine);\r
- }\r
-\r
- /**\r
- * @return checksum or null if checksum not exists for line\r
- */\r
- private String getChecksumForLine(List<String> checksums, Integer line) {\r
- if (line == null || line < 1 || line > checksums.size()) {\r
- return null;\r
- }\r
- return checksums.get(line - 1);\r
- }\r
-\r
- /**\r
- * Search for past violation.\r
- */\r
- RuleFailureModel selectPastViolation(Violation violation, Multimap<Rule, RuleFailureModel> pastViolationsByRule) {\r
- Collection<RuleFailureModel> pastViolations = pastViolationsByRule.get(violation.getRule());\r
- if (pastViolations==null || pastViolations.isEmpty()) {\r
- // skip violation, if there is no past violations with same rule\r
- return null;\r
- }\r
- String dbFormattedMessage = RuleFailureModel.abbreviateMessage(violation.getMessage());\r
- RuleFailureModel found = selectPastViolationUsingLine(violation, dbFormattedMessage, pastViolations);\r
- if (found == null) {\r
- found = selectPastViolationUsingChecksum(violation, dbFormattedMessage, pastViolations);\r
- }\r
- return found;\r
- }\r
-\r
- /**\r
- * Search for past violation with same message and line.\r
- */\r
- private RuleFailureModel selectPastViolationUsingLine(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) {\r
- for (RuleFailureModel pastViolation : pastViolations) {\r
- if (ObjectUtils.equals(violation.getLineId(), pastViolation.getLine()) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) {\r
- return pastViolation;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * Search for past violation with same message and checksum.\r
- */\r
- private RuleFailureModel selectPastViolationUsingChecksum(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) {\r
- String checksum = getChecksumForLine(checksums, violation.getLineId());\r
- // skip violation, which not attached to line\r
- if (checksum == null) {\r
- return null;\r
- }\r
- for (RuleFailureModel pastViolation : pastViolations) {\r
- String pastChecksum = pastViolation.getChecksum();\r
- if (StringUtils.equals(checksum, pastChecksum) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) {\r
- return pastViolation;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return getClass().getSimpleName();\r
- }\r
-\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.plugins.core.timemachine;
+
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.plexus.util.StringInputStream;
+import org.sonar.api.batch.*;
+import org.sonar.api.database.model.RuleFailureModel;
+import org.sonar.api.database.model.SnapshotSource;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.Violation;
+import org.sonar.api.utils.SonarException;
+import org.sonar.batch.components.PastViolationsLoader;
+import org.sonar.batch.index.ViolationPersister;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+@DependsUpon(DecoratorBarriers.END_OF_VIOLATIONS_GENERATION)
+@DependedUpon("ViolationPersisterDecorator") /* temporary workaround - see NewViolationsDecorator */
+public class ViolationPersisterDecorator implements Decorator {
+
+ /**
+ * Those chars would be ignored during generation of checksums.
+ */
+ private static final String SPACE_CHARS = "\t\n\r ";
+
+ private RuleFinder ruleFinder;
+ private PastViolationsLoader pastViolationsLoader;
+ private ViolationPersister violationPersister;
+
+ List<String> checksums = Lists.newArrayList();
+
+ public ViolationPersisterDecorator(RuleFinder ruleFinder, PastViolationsLoader pastViolationsLoader, ViolationPersister violationPersister) {
+ this.ruleFinder = ruleFinder;
+ this.pastViolationsLoader = pastViolationsLoader;
+ this.violationPersister = violationPersister;
+ }
+
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+
+ public void decorate(Resource resource, DecoratorContext context) {
+ if (context.getViolations().isEmpty()) {
+ return;
+ }
+ // Load past violations
+ List<RuleFailureModel> pastViolations = pastViolationsLoader.getPastViolations(resource);
+ // Load current source and calculate checksums
+ checksums = getChecksums(pastViolationsLoader.getSource(resource));
+ // Save violations
+ compareWithPastViolations(context, pastViolations);
+ // Clear cache
+ checksums.clear();
+ }
+
+ private void compareWithPastViolations(DecoratorContext context, List<RuleFailureModel> pastViolations) {
+ Multimap<Rule, RuleFailureModel> pastViolationsByRule = LinkedHashMultimap.create();
+ for (RuleFailureModel pastViolation : pastViolations) {
+ Rule rule = ruleFinder.findById(pastViolation.getRuleId());
+ pastViolationsByRule.put(rule, pastViolation);
+ }
+ // for each violation, search equivalent past violation
+ for (Violation violation : context.getViolations()) {
+ RuleFailureModel pastViolation = selectPastViolation(violation, pastViolationsByRule);
+ if (pastViolation != null) {
+ // remove violation, since would be updated and shouldn't affect other violations anymore
+ pastViolationsByRule.remove(violation.getRule(), pastViolation);
+ }
+ String checksum = getChecksumForLine(checksums, violation.getLineId());
+ violationPersister.saveViolation(context.getProject(), violation, pastViolation, checksum);
+ }
+ violationPersister.commit();
+ }
+
+ /**
+ * @return checksums, never null
+ */
+ private List<String> getChecksums(SnapshotSource source) {
+ return source == null || source.getData() == null ? Collections.<String>emptyList() : getChecksums(source.getData());
+ }
+
+ static List<String> getChecksums(String data) {
+ List<String> result = Lists.newArrayList();
+ StringInputStream stream = new StringInputStream(data);
+ try {
+ List<String> lines = IOUtils.readLines(stream);
+ for (String line : lines) {
+ result.add(getChecksum(line));
+ }
+ } catch (IOException e) {
+ throw new SonarException("Unable to calculate checksums", e);
+
+ } finally {
+ IOUtils.closeQuietly(stream);
+ }
+ return result;
+ }
+
+ static String getChecksum(String line) {
+ String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, "");
+ return DigestUtils.md5Hex(reducedLine);
+ }
+
+ /**
+ * @return checksum or null if checksum not exists for line
+ */
+ private String getChecksumForLine(List<String> checksums, Integer line) {
+ if (line == null || line < 1 || line > checksums.size()) {
+ return null;
+ }
+ return checksums.get(line - 1);
+ }
+
+ /**
+ * Search for past violation.
+ */
+ RuleFailureModel selectPastViolation(Violation violation, Multimap<Rule, RuleFailureModel> pastViolationsByRule) {
+ Collection<RuleFailureModel> pastViolations = pastViolationsByRule.get(violation.getRule());
+ if (pastViolations==null || pastViolations.isEmpty()) {
+ // skip violation, if there is no past violations with same rule
+ return null;
+ }
+ String dbFormattedMessage = RuleFailureModel.abbreviateMessage(violation.getMessage());
+ RuleFailureModel found = selectPastViolationUsingLine(violation, dbFormattedMessage, pastViolations);
+ if (found == null) {
+ found = selectPastViolationUsingChecksum(violation, dbFormattedMessage, pastViolations);
+ }
+ return found;
+ }
+
+ /**
+ * Search for past violation with same message and line.
+ */
+ private RuleFailureModel selectPastViolationUsingLine(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) {
+ for (RuleFailureModel pastViolation : pastViolations) {
+ if (ObjectUtils.equals(violation.getLineId(), pastViolation.getLine()) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) {
+ return pastViolation;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Search for past violation with same message and checksum.
+ */
+ private RuleFailureModel selectPastViolationUsingChecksum(Violation violation, String dbFormattedMessage, Collection<RuleFailureModel> pastViolations) {
+ String checksum = getChecksumForLine(checksums, violation.getLineId());
+ // skip violation, which not attached to line
+ if (checksum == null) {
+ return null;
+ }
+ for (RuleFailureModel pastViolation : pastViolations) {
+ String pastChecksum = pastViolation.getChecksum();
+ if (StringUtils.equals(checksum, pastChecksum) && StringUtils.equals(dbFormattedMessage, pastViolation.getMessage())) {
+ return pastViolation;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+
}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.plugins.core.sensors;\r
-\r
-import org.junit.Ignore;\r
-import org.junit.Test;\r
-import org.sonar.api.database.model.Snapshot;\r
-import org.sonar.api.resources.File;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.api.utils.DateUtils;\r
-import org.sonar.batch.components.PastSnapshot;\r
-import org.sonar.batch.components.TimeMachineConfiguration;\r
-import org.sonar.batch.index.ResourcePersister;\r
-import org.sonar.jpa.test.AbstractDbUnitTestCase;\r
-\r
-import java.text.ParseException;\r
-import java.util.Arrays;\r
-\r
-import static org.mockito.Mockito.mock;\r
-import static org.mockito.Mockito.when;\r
-\r
-public class ReviewsDecoratorTest extends AbstractDbUnitTestCase {\r
-\r
- @Test\r
- @Ignore("DBUnit needs Hibernate mapping...")\r
- public void shouldSaveConfigurationInSnapshotsTable() throws ParseException {\r
- setupData("fixture");\r
- \r
- File resource = new File("Foo");\r
- Snapshot snapshot = new Snapshot();\r
- snapshot.setId(666);\r
- snapshot.setResourceId(111);\r
- ResourcePersister persister = mock(ResourcePersister.class);\r
- when(persister.getSnapshot(resource)).thenReturn(snapshot);\r
-\r
- ReviewsDecorator reviewsDecorator = new ReviewsDecorator(persister, getSession());\r
- reviewsDecorator.decorate(resource, null);\r
-\r
- //checkTables("shouldSaveConfigurationInSnapshotsTable", "snapshots");\r
- }\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.plugins.core.sensors;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.File;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.TimeMachineConfiguration;
+import org.sonar.batch.index.ResourcePersister;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import java.text.ParseException;
+import java.util.Arrays;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ReviewsDecoratorTest extends AbstractDbUnitTestCase {
+
+ @Test
+ @Ignore("DBUnit needs Hibernate mapping...")
+ public void shouldSaveConfigurationInSnapshotsTable() throws ParseException {
+ setupData("fixture");
+
+ File resource = new File("Foo");
+ Snapshot snapshot = new Snapshot();
+ snapshot.setId(666);
+ snapshot.setResourceId(111);
+ ResourcePersister persister = mock(ResourcePersister.class);
+ when(persister.getSnapshot(resource)).thenReturn(snapshot);
+
+ ReviewsDecorator reviewsDecorator = new ReviewsDecorator(persister, getSession());
+ reviewsDecorator.decorate(resource, null);
+
+ //checkTables("shouldSaveConfigurationInSnapshotsTable", "snapshots");
+ }
+}
-<dataset>\r
-\r
- <snapshots \r
- id="11" \r
- project_id="555"/>\r
- <snapshots \r
- id="111" \r
- project_id="555"/>\r
- <snapshots \r
- id="22" \r
- project_id="666"/>\r
- <snapshots \r
- id="222" \r
- project_id="666"/>\r
-\r
- <rule_failures \r
- id="1"\r
- permament_id="1"\r
- snapshot_id="11"/>\r
- <rule_failures \r
- id="2"\r
- permament_id="2"\r
- snapshot_id="22"/>\r
- <rule_failures \r
- id="3"\r
- permament_id="3"\r
- snapshot_id="22"/>\r
- <rule_failures \r
- id="4"\r
- permament_id="1"\r
- snapshot_id="111"/>\r
- <rule_failures \r
- id="5"\r
- permament_id="3"\r
- snapshot_id="222"/>\r
-\r
- <reviews\r
- id="1"\r
- status="open"\r
- rule_failure_permanent_id="1"\r
- resource_id="555"/>\r
- <reviews\r
- id="2"\r
- status="open"\r
- rule_failure_permanent_id="2"\r
- resource_id="666"/>\r
- <reviews\r
- id="3"\r
- status="open"\r
- rule_failure_permanent_id="3"\r
- resource_id="666"/>\r
-\r
+<dataset>
+
+ <snapshots
+ id="11"
+ project_id="555"/>
+ <snapshots
+ id="111"
+ project_id="555"/>
+ <snapshots
+ id="22"
+ project_id="666"/>
+ <snapshots
+ id="222"
+ project_id="666"/>
+
+ <rule_failures
+ id="1"
+ permament_id="1"
+ snapshot_id="11"/>
+ <rule_failures
+ id="2"
+ permament_id="2"
+ snapshot_id="22"/>
+ <rule_failures
+ id="3"
+ permament_id="3"
+ snapshot_id="22"/>
+ <rule_failures
+ id="4"
+ permament_id="1"
+ snapshot_id="111"/>
+ <rule_failures
+ id="5"
+ permament_id="3"
+ snapshot_id="222"/>
+
+ <reviews
+ id="1"
+ status="open"
+ rule_failure_permanent_id="1"
+ resource_id="555"/>
+ <reviews
+ id="2"
+ status="open"
+ rule_failure_permanent_id="2"
+ resource_id="666"/>
+ <reviews
+ id="3"
+ status="open"
+ rule_failure_permanent_id="3"
+ resource_id="666"/>
+
</dataset>
\ No newline at end of file
set MAVEN_OPTS=-Xmx768m -XX:MaxPermSize=256m
-mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev
\ No newline at end of file
+mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev
echo '-------------------------------------------------'
# it is recommended to use maven 3 for faster builds
-mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev
\ No newline at end of file
+mvn clean install -Dtest=false -DfailIfNoTests=false -Ddev
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.batch;\r
-\r
-import java.util.Collection;\r
-import java.util.Date;\r
-import java.util.List;\r
-import java.util.Set;\r
-\r
-import com.google.common.collect.Lists;\r
-import org.sonar.api.batch.DecoratorContext;\r
-import org.sonar.api.batch.Event;\r
-import org.sonar.api.batch.SonarIndex;\r
-import org.sonar.api.design.Dependency;\r
-import org.sonar.api.measures.Measure;\r
-import org.sonar.api.measures.MeasuresFilter;\r
-import org.sonar.api.measures.MeasuresFilters;\r
-import org.sonar.api.measures.Metric;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.api.violations.ViolationQuery;\r
-\r
-public class DefaultDecoratorContext implements DecoratorContext {\r
-\r
- private SonarIndex index;\r
- private Resource resource;\r
- private boolean readOnly = false;\r
-\r
- private List<DecoratorContext> childrenContexts;\r
-\r
- public DefaultDecoratorContext(Resource resource,\r
- SonarIndex index,\r
- List<DecoratorContext> childrenContexts) {\r
- this.index = index;\r
- this.resource = resource;\r
- this.childrenContexts = childrenContexts;\r
- }\r
-\r
- public DefaultDecoratorContext setReadOnly(boolean b) {\r
- readOnly = b;\r
- childrenContexts = null;\r
- return this;\r
- }\r
-\r
- public Project getProject() {\r
- return index.getProject();\r
- }\r
-\r
- public List<DecoratorContext> getChildren() {\r
- checkReadOnly("getModules");\r
- return childrenContexts;\r
- }\r
-\r
- private void checkReadOnly(String methodName) {\r
- if (readOnly) {\r
- throw new IllegalStateException("Method DecoratorContext." + methodName + "() can not be executed on children.");\r
- }\r
- }\r
-\r
- public <M> M getMeasures(MeasuresFilter<M> filter) {\r
- return index.getMeasures(resource, filter);\r
- }\r
-\r
- public Measure getMeasure(Metric metric) {\r
- return index.getMeasure(resource, metric);\r
- }\r
-\r
- public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) {\r
- List<Measure> result = Lists.newArrayList();\r
- for (DecoratorContext childContext : childrenContexts) {\r
- Object childResult = childContext.getMeasures(filter);\r
- if (childResult != null) {\r
- if (childResult instanceof Collection) {\r
- result.addAll((Collection) childResult);\r
- } else {\r
- result.add((Measure) childResult);\r
- }\r
- }\r
- }\r
- return result;\r
- }\r
-\r
- public Collection<Measure> getChildrenMeasures(Metric metric) {\r
- return getChildrenMeasures(MeasuresFilters.metric(metric));\r
- }\r
-\r
- public Resource getResource() {\r
- return resource;\r
- }\r
-\r
- public DecoratorContext saveMeasure(Measure measure) {\r
- checkReadOnly("saveMeasure");\r
- index.addMeasure(resource, measure);\r
- return this;\r
- }\r
-\r
- public DecoratorContext saveMeasure(Metric metric, Double value) {\r
- checkReadOnly("saveMeasure");\r
- index.addMeasure(resource, new Measure(metric, value));\r
- return this;\r
- }\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- public List<Violation> getViolations(ViolationQuery violationQuery) {\r
- return index.getViolations(violationQuery);\r
- }\r
- \r
- /**\r
- * {@inheritDoc}\r
- */\r
- public List<Violation> getViolations() {\r
- return index.getViolations(resource);\r
- }\r
-\r
- public Dependency saveDependency(Dependency dependency) {\r
- checkReadOnly("addDependency");\r
- return index.addDependency(dependency);\r
- }\r
-\r
- public Set<Dependency> getDependencies() {\r
- return index.getDependencies();\r
- }\r
-\r
- public Collection<Dependency> getIncomingDependencies() {\r
- return index.getIncomingEdges(resource);\r
- }\r
-\r
- public Collection<Dependency> getOutgoingDependencies() {\r
- return index.getOutgoingEdges(resource);\r
- }\r
-\r
- public List<Event> getEvents() {\r
- return index.getEvents(resource);\r
- }\r
-\r
- public Event createEvent(String name, String description, String category, Date date) {\r
- return index.addEvent(resource, name, description, category, date);\r
- }\r
-\r
- public void deleteEvent(Event event) {\r
- index.deleteEvent(event);\r
- }\r
-\r
- public DefaultDecoratorContext saveViolation(Violation violation, boolean force) {\r
- if (violation.getResource() == null) {\r
- violation.setResource(resource);\r
- }\r
- index.addViolation(violation, force);\r
- return this;\r
- }\r
-\r
- public DefaultDecoratorContext saveViolation(Violation violation) {\r
- return saveViolation(violation, false);\r
- }\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.batch;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.Lists;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.Event;
+import org.sonar.api.batch.SonarIndex;
+import org.sonar.api.design.Dependency;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.MeasuresFilter;
+import org.sonar.api.measures.MeasuresFilters;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rules.Violation;
+import org.sonar.api.violations.ViolationQuery;
+
+public class DefaultDecoratorContext implements DecoratorContext {
+
+ private SonarIndex index;
+ private Resource resource;
+ private boolean readOnly = false;
+
+ private List<DecoratorContext> childrenContexts;
+
+ public DefaultDecoratorContext(Resource resource,
+ SonarIndex index,
+ List<DecoratorContext> childrenContexts) {
+ this.index = index;
+ this.resource = resource;
+ this.childrenContexts = childrenContexts;
+ }
+
+ public DefaultDecoratorContext setReadOnly(boolean b) {
+ readOnly = b;
+ childrenContexts = null;
+ return this;
+ }
+
+ public Project getProject() {
+ return index.getProject();
+ }
+
+ public List<DecoratorContext> getChildren() {
+ checkReadOnly("getModules");
+ return childrenContexts;
+ }
+
+ private void checkReadOnly(String methodName) {
+ if (readOnly) {
+ throw new IllegalStateException("Method DecoratorContext." + methodName + "() can not be executed on children.");
+ }
+ }
+
+ public <M> M getMeasures(MeasuresFilter<M> filter) {
+ return index.getMeasures(resource, filter);
+ }
+
+ public Measure getMeasure(Metric metric) {
+ return index.getMeasure(resource, metric);
+ }
+
+ public Collection<Measure> getChildrenMeasures(MeasuresFilter filter) {
+ List<Measure> result = Lists.newArrayList();
+ for (DecoratorContext childContext : childrenContexts) {
+ Object childResult = childContext.getMeasures(filter);
+ if (childResult != null) {
+ if (childResult instanceof Collection) {
+ result.addAll((Collection) childResult);
+ } else {
+ result.add((Measure) childResult);
+ }
+ }
+ }
+ return result;
+ }
+
+ public Collection<Measure> getChildrenMeasures(Metric metric) {
+ return getChildrenMeasures(MeasuresFilters.metric(metric));
+ }
+
+ public Resource getResource() {
+ return resource;
+ }
+
+ public DecoratorContext saveMeasure(Measure measure) {
+ checkReadOnly("saveMeasure");
+ index.addMeasure(resource, measure);
+ return this;
+ }
+
+ public DecoratorContext saveMeasure(Metric metric, Double value) {
+ checkReadOnly("saveMeasure");
+ index.addMeasure(resource, new Measure(metric, value));
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<Violation> getViolations(ViolationQuery violationQuery) {
+ return index.getViolations(violationQuery);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<Violation> getViolations() {
+ return index.getViolations(resource);
+ }
+
+ public Dependency saveDependency(Dependency dependency) {
+ checkReadOnly("addDependency");
+ return index.addDependency(dependency);
+ }
+
+ public Set<Dependency> getDependencies() {
+ return index.getDependencies();
+ }
+
+ public Collection<Dependency> getIncomingDependencies() {
+ return index.getIncomingEdges(resource);
+ }
+
+ public Collection<Dependency> getOutgoingDependencies() {
+ return index.getOutgoingEdges(resource);
+ }
+
+ public List<Event> getEvents() {
+ return index.getEvents(resource);
+ }
+
+ public Event createEvent(String name, String description, String category, Date date) {
+ return index.addEvent(resource, name, description, category, date);
+ }
+
+ public void deleteEvent(Event event) {
+ index.deleteEvent(event);
+ }
+
+ public DefaultDecoratorContext saveViolation(Violation violation, boolean force) {
+ if (violation.getResource() == null) {
+ violation.setResource(resource);
+ }
+ index.addViolation(violation, force);
+ return this;
+ }
+
+ public DefaultDecoratorContext saveViolation(Violation violation) {
+ return saveViolation(violation, false);
+ }
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.batch.index;\r
-\r
-import com.google.common.collect.Lists;\r
-import com.google.common.collect.Maps;\r
-import com.google.common.collect.Sets;\r
-import org.apache.commons.lang.ObjectUtils;\r
-import org.apache.commons.lang.StringUtils;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-import org.sonar.api.batch.Event;\r
-import org.sonar.api.batch.SonarIndex;\r
-import org.sonar.api.database.model.ResourceModel;\r
-import org.sonar.api.design.Dependency;\r
-import org.sonar.api.measures.*;\r
-import org.sonar.api.profiles.RulesProfile;\r
-import org.sonar.api.resources.*;\r
-import org.sonar.api.rules.ActiveRule;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.api.utils.SonarException;\r
-import org.sonar.api.violations.ViolationQuery;\r
-import org.sonar.batch.DefaultResourceCreationLock;\r
-import org.sonar.batch.ProjectTree;\r
-import org.sonar.batch.ResourceFilters;\r
-import org.sonar.batch.ViolationFilters;\r
-\r
-import java.util.*;\r
-\r
-public class DefaultIndex extends SonarIndex {\r
-\r
- private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);\r
-\r
- private RulesProfile profile;\r
- private PersistenceManager persistence;\r
- private DefaultResourceCreationLock lock;\r
- private MetricFinder metricFinder;\r
-\r
- // filters\r
- private ViolationFilters violationFilters;\r
- private ResourceFilters resourceFilters;\r
-\r
- // caches\r
- private Project currentProject;\r
- private Map<Resource, Bucket> buckets = Maps.newHashMap();\r
- private Set<Dependency> dependencies = Sets.newHashSet();\r
- private Map<Resource, Map<Resource, Dependency>> outgoingDependenciesByResource = Maps.newHashMap();\r
- private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newHashMap();\r
- private ProjectTree projectTree;\r
-\r
- public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder) {\r
- this.persistence = persistence;\r
- this.lock = lock;\r
- this.projectTree = projectTree;\r
- this.metricFinder = metricFinder;\r
- }\r
-\r
- public void start() {\r
- Project rootProject = projectTree.getRootProject();\r
- doStart(rootProject);\r
- }\r
-\r
- void doStart(Project rootProject) {\r
- Bucket bucket = new Bucket(rootProject);\r
- buckets.put(rootProject, bucket);\r
- persistence.saveProject(rootProject, null);\r
- currentProject = rootProject;\r
-\r
- for (Project project : rootProject.getModules()) {\r
- addProject(project);\r
- }\r
- }\r
-\r
- private void addProject(Project project) {\r
- addResource(project);\r
- for (Project module : project.getModules()) {\r
- addProject(module);\r
- }\r
- }\r
-\r
- public Project getProject() {\r
- return currentProject;\r
- }\r
-\r
- public void setCurrentProject(Project project, ResourceFilters resourceFilters, ViolationFilters violationFilters, RulesProfile profile) {\r
- this.currentProject = project;\r
-\r
- // the following components depend on the current project, so they need to be reloaded.\r
- this.resourceFilters = resourceFilters;\r
- this.violationFilters = violationFilters;\r
- this.profile = profile;\r
- }\r
-\r
- /**\r
- * Keep only project stuff\r
- */\r
- public void clear() {\r
- Iterator<Map.Entry<Resource, Bucket>> it = buckets.entrySet().iterator();\r
- while (it.hasNext()) {\r
- Map.Entry<Resource, Bucket> entry = it.next();\r
- Resource resource = entry.getKey();\r
- if (!ResourceUtils.isSet(resource)) {\r
- entry.getValue().clear();\r
- it.remove();\r
- }\r
- }\r
-\r
- Set<Dependency> projectDependencies = getDependenciesBetweenProjects();\r
- dependencies.clear();\r
- incomingDependenciesByResource.clear();\r
- outgoingDependenciesByResource.clear();\r
- for (Dependency projectDependency : projectDependencies) {\r
- projectDependency.setId(null);\r
- registerDependency(projectDependency);\r
- }\r
-\r
- lock.unlock();\r
- }\r
-\r
- public Measure getMeasure(Resource resource, Metric metric) {\r
- Bucket bucket = buckets.get(resource);\r
- if (bucket != null) {\r
- Measure measure = bucket.getMeasures(MeasuresFilters.metric(metric));\r
- if (measure != null) {\r
- return persistence.reloadMeasure(measure);\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- public <M> M getMeasures(Resource resource, MeasuresFilter<M> filter) {\r
- Bucket bucket = buckets.get(resource);\r
- if (bucket != null) {\r
- // TODO the data measures which are not kept in memory are not reloaded yet. Use getMeasure().\r
- return bucket.getMeasures(filter);\r
- }\r
- return null;\r
- }\r
-\r
- /**\r
- * the measure is updated if it's already registered.\r
- */\r
- public Measure addMeasure(Resource resource, Measure measure) {\r
- Bucket bucket = checkIndexed(resource);\r
- if (bucket != null && !bucket.isExcluded()) {\r
- Metric metric = metricFinder.findByKey(measure.getMetricKey());\r
- if (metric == null) {\r
- throw new SonarException("Unknown metric: " + measure.getMetricKey());\r
- }\r
- measure.setMetric(metric);\r
- bucket.addMeasure(measure);\r
-\r
- if (measure.getPersistenceMode().useDatabase()) {\r
- persistence.saveMeasure(resource, measure);\r
- }\r
- }\r
- return measure;\r
- }\r
-\r
- //\r
- //\r
- //\r
- // DEPENDENCIES\r
- //\r
- //\r
- //\r
-\r
- public Dependency addDependency(Dependency dependency) {\r
- Dependency existingDep = getEdge(dependency.getFrom(), dependency.getTo());\r
- if (existingDep != null) {\r
- return existingDep;\r
- }\r
-\r
- Dependency parentDependency = dependency.getParent();\r
- if (parentDependency != null) {\r
- addDependency(parentDependency);\r
- }\r
-\r
- if (registerDependency(dependency)) {\r
- persistence.saveDependency(currentProject, dependency, parentDependency);\r
- }\r
- return dependency;\r
- }\r
-\r
- boolean registerDependency(Dependency dependency) {\r
- Bucket fromBucket = doIndex(dependency.getFrom());\r
- Bucket toBucket = doIndex(dependency.getTo());\r
-\r
- if (fromBucket != null && !fromBucket.isExcluded() && toBucket != null && !toBucket.isExcluded()) {\r
- dependencies.add(dependency);\r
- registerOutgoingDependency(dependency);\r
- registerIncomingDependency(dependency);\r
- return true;\r
- }\r
- return false;\r
- }\r
-\r
- private void registerOutgoingDependency(Dependency dependency) {\r
- Map<Resource, Dependency> outgoingDeps = outgoingDependenciesByResource.get(dependency.getFrom());\r
- if (outgoingDeps == null) {\r
- outgoingDeps = new HashMap<Resource, Dependency>();\r
- outgoingDependenciesByResource.put(dependency.getFrom(), outgoingDeps);\r
- }\r
- outgoingDeps.put(dependency.getTo(), dependency);\r
- }\r
-\r
- private void registerIncomingDependency(Dependency dependency) {\r
- Map<Resource, Dependency> incomingDeps = incomingDependenciesByResource.get(dependency.getTo());\r
- if (incomingDeps == null) {\r
- incomingDeps = new HashMap<Resource, Dependency>();\r
- incomingDependenciesByResource.put(dependency.getTo(), incomingDeps);\r
- }\r
- incomingDeps.put(dependency.getFrom(), dependency);\r
- }\r
-\r
- public Set<Dependency> getDependencies() {\r
- return dependencies;\r
- }\r
-\r
- public Dependency getEdge(Resource from, Resource to) {\r
- Map<Resource, Dependency> map = outgoingDependenciesByResource.get(from);\r
- if (map != null) {\r
- return map.get(to);\r
- }\r
- return null;\r
- }\r
-\r
- public boolean hasEdge(Resource from, Resource to) {\r
- return getEdge(from, to) != null;\r
- }\r
-\r
- public Set<Resource> getVertices() {\r
- return buckets.keySet();\r
- }\r
-\r
- public Collection<Dependency> getOutgoingEdges(Resource from) {\r
- Map<Resource, Dependency> deps = outgoingDependenciesByResource.get(from);\r
- if (deps != null) {\r
- return deps.values();\r
- }\r
- return Collections.emptyList();\r
- }\r
-\r
- public Collection<Dependency> getIncomingEdges(Resource to) {\r
- Map<Resource, Dependency> deps = incomingDependenciesByResource.get(to);\r
- if (deps != null) {\r
- return deps.values();\r
- }\r
- return Collections.emptyList();\r
- }\r
-\r
- Set<Dependency> getDependenciesBetweenProjects() {\r
- Set<Dependency> result = Sets.newLinkedHashSet();\r
- for (Dependency dependency : dependencies) {\r
- if (ResourceUtils.isSet(dependency.getFrom()) || ResourceUtils.isSet(dependency.getTo())) {\r
- result.add(dependency);\r
- }\r
- }\r
- return result;\r
- }\r
-\r
- //\r
- //\r
- //\r
- // VIOLATIONS\r
- //\r
- //\r
- //\r
-\r
- /**\r
- * {@inheritDoc}\r
- */\r
- public List<Violation> getViolations(ViolationQuery violationQuery) {\r
- Resource resource = violationQuery.getResource();\r
- if (resource == null) {\r
- throw new IllegalArgumentException("A resource must be set on the ViolationQuery in order to search for violations.");\r
- }\r
- Bucket bucket = buckets.get(resource);\r
- if (bucket == null) {\r
- return Collections.emptyList();\r
- }\r
- List<Violation> filteredViolations = Lists.newArrayList();\r
- boolean ignoreSwitchedOff = violationQuery.ignoreSwitchedOff();\r
- for (Violation violation : bucket.getViolations()) {\r
- if ( ignoreSwitchedOff && violation.isSwitchedOff()) {\r
- continue;\r
- }\r
- filteredViolations.add(violation);\r
- }\r
- return filteredViolations;\r
- }\r
-\r
- public void addViolation(Violation violation, boolean force) {\r
- Resource resource = violation.getResource();\r
- if (resource == null) {\r
- violation.setResource(currentProject);\r
- } else if (!Scopes.isHigherThanOrEquals(resource, Scopes.FILE)) {\r
- throw new IllegalArgumentException("Violations are only supported on files, directories and project");\r
- }\r
-\r
- if (violation.getRule() == null) {\r
- LOG.warn("Rule is null, ignoring violation {}", violation);\r
- return;\r
- }\r
-\r
- Bucket bucket = checkIndexed(resource);\r
- if (bucket != null && !bucket.isExcluded()) {\r
- boolean isIgnored = !force && violationFilters != null && violationFilters.isIgnored(violation);\r
- if (!isIgnored) {\r
- ActiveRule activeRule = profile.getActiveRule(violation.getRule());\r
- if (activeRule == null) {\r
- if (currentProject.getReuseExistingRulesConfig()) {\r
- violation.setSeverity(violation.getRule().getSeverity());\r
- doAddViolation(violation, bucket);\r
-\r
- } else {\r
- LoggerFactory.getLogger(getClass()).debug("Rule is not activated, ignoring violation {}", violation);\r
- }\r
-\r
- } else {\r
- violation.setSeverity(activeRule.getSeverity());\r
- doAddViolation(violation, bucket);\r
- }\r
- }\r
- }\r
- }\r
-\r
- private void doAddViolation(Violation violation, Bucket bucket) {\r
- bucket.addViolation(violation);\r
- }\r
-\r
- //\r
- //\r
- //\r
- // LINKS\r
- //\r
- //\r
- //\r
-\r
- public void addLink(ProjectLink link) {\r
- persistence.saveLink(currentProject, link);\r
- }\r
-\r
- public void deleteLink(String key) {\r
- persistence.deleteLink(currentProject, key);\r
- }\r
-\r
- //\r
- //\r
- //\r
- // EVENTS\r
- //\r
- //\r
- //\r
-\r
- public List<Event> getEvents(Resource resource) {\r
- // currently events are not cached in memory\r
- return persistence.getEvents(resource);\r
- }\r
-\r
- public void deleteEvent(Event event) {\r
- persistence.deleteEvent(event);\r
- }\r
-\r
- public Event addEvent(Resource resource, String name, String description, String category, Date date) {\r
- Event event = new Event(name, description, category);\r
- event.setDate(date);\r
- persistence.saveEvent(resource, event);\r
- return null;\r
- }\r
-\r
- public void setSource(Resource reference, String source) {\r
- Bucket bucket = checkIndexed(reference);\r
- if (bucket != null && !bucket.isExcluded()) {\r
- persistence.setSource(reference, source);\r
- }\r
- }\r
-\r
- /**\r
- * Does nothing if the resource is already registered.\r
- */\r
- public Resource addResource(Resource resource) {\r
- Bucket bucket = doIndex(resource);\r
- return bucket != null ? bucket.getResource() : null;\r
- }\r
-\r
- public <R extends Resource> R getResource(R reference) {\r
- Bucket bucket = buckets.get(reference);\r
- if (bucket != null) {\r
- return (R) bucket.getResource();\r
- }\r
- return null;\r
- }\r
-\r
- static String createUID(Project project, Resource resource) {\r
- String uid = resource.getKey();\r
- if (!StringUtils.equals(Scopes.PROJECT, resource.getScope())) {\r
- // not a project nor a library\r
- uid = new StringBuilder(ResourceModel.KEY_SIZE)\r
- .append(project.getKey())\r
- .append(':')\r
- .append(resource.getKey())\r
- .toString();\r
- }\r
- return uid;\r
- }\r
-\r
- private boolean checkExclusion(Resource resource, Bucket parent) {\r
- boolean excluded = (parent != null && parent.isExcluded()) || (resourceFilters != null && resourceFilters.isExcluded(resource));\r
- resource.setExcluded(excluded);\r
- return excluded;\r
- }\r
-\r
- public List<Resource> getChildren(Resource resource) {\r
- return getChildren(resource, false);\r
- }\r
-\r
- public List<Resource> getChildren(Resource resource, boolean acceptExcluded) {\r
- List<Resource> children = Lists.newLinkedList();\r
- Bucket bucket = getBucket(resource, acceptExcluded);\r
- if (bucket != null) {\r
- for (Bucket childBucket : bucket.getChildren()) {\r
- if (acceptExcluded || !childBucket.isExcluded()) {\r
- children.add(childBucket.getResource());\r
- }\r
- }\r
- }\r
- return children;\r
- }\r
-\r
- public Resource getParent(Resource resource) {\r
- Bucket bucket = getBucket(resource, false);\r
- if (bucket != null && bucket.getParent() != null) {\r
- return bucket.getParent().getResource();\r
- }\r
- return null;\r
- }\r
-\r
- public boolean index(Resource resource) {\r
- Bucket bucket = doIndex(resource);\r
- return bucket != null && !bucket.isExcluded();\r
- }\r
-\r
- private Bucket doIndex(Resource resource) {\r
- if (resource.getParent() != null) {\r
- doIndex(resource.getParent());\r
- }\r
- return doIndex(resource, resource.getParent());\r
- }\r
-\r
- public boolean index(Resource resource, Resource parentReference) {\r
- Bucket bucket = doIndex(resource, parentReference);\r
- return bucket != null && !bucket.isExcluded();\r
- }\r
-\r
- private Bucket doIndex(Resource resource, Resource parentReference) {\r
- Bucket bucket = buckets.get(resource);\r
- if (bucket != null) {\r
- return bucket;\r
- }\r
-\r
- checkLock(resource);\r
-\r
- Resource parent = null;\r
- if (!ResourceUtils.isLibrary(resource)) {\r
- // a library has no parent\r
- parent = (Resource) ObjectUtils.defaultIfNull(parentReference, currentProject);\r
- }\r
-\r
- Bucket parentBucket = getBucket(parent, true);\r
- if (parentBucket == null && parent != null) {\r
- LOG.warn("Resource ignored, parent is not indexed: " + resource);\r
- return null;\r
- }\r
-\r
- resource.setEffectiveKey(createUID(currentProject, resource));\r
- bucket = new Bucket(resource).setParent(parentBucket);\r
- buckets.put(resource, bucket);\r
-\r
- boolean excluded = checkExclusion(resource, parentBucket);\r
- if (!excluded) {\r
- persistence.saveResource(currentProject, resource, (parentBucket != null ? parentBucket.getResource() : null));\r
- }\r
- return bucket;\r
- }\r
-\r
- private void checkLock(Resource resource) {\r
- if (lock.isLocked() && !ResourceUtils.isLibrary(resource)) {\r
- if (lock.isFailWhenLocked()) {\r
- throw new SonarException("Index is locked, resource can not be indexed: " + resource);\r
- }\r
- }\r
- }\r
-\r
- private Bucket checkIndexed(Resource resource) {\r
- Bucket bucket = getBucket(resource, true);\r
- if (bucket == null) {\r
- if (lock.isLocked()) {\r
- if (lock.isFailWhenLocked()) {\r
- throw new ResourceNotIndexedException(resource);\r
- }\r
- LOG.warn("Resource will be ignored in next Sonar versions, index is locked: " + resource);\r
- }\r
- if (Scopes.isDirectory(resource) || Scopes.isFile(resource)) {\r
- bucket = doIndex(resource);\r
- } else if (!lock.isLocked()) {\r
- LOG.warn("Resource will be ignored in next Sonar versions, it must be indexed before adding data: " + resource);\r
- }\r
- }\r
- return bucket;\r
- }\r
-\r
- public boolean isExcluded(Resource reference) {\r
- Bucket bucket = getBucket(reference, true);\r
- return bucket != null && bucket.isExcluded();\r
- }\r
-\r
- public boolean isIndexed(Resource reference, boolean acceptExcluded) {\r
- return getBucket(reference, acceptExcluded) != null;\r
- }\r
-\r
- private Bucket getBucket(Resource resource, boolean acceptExcluded) {\r
- Bucket bucket = null;\r
- if (resource != null) {\r
- bucket = buckets.get(resource);\r
- if (!acceptExcluded && bucket != null && bucket.isExcluded()) {\r
- bucket = null;\r
- }\r
- }\r
- return bucket;\r
- }\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.batch.index;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.Event;
+import org.sonar.api.batch.SonarIndex;
+import org.sonar.api.database.model.ResourceModel;
+import org.sonar.api.design.Dependency;
+import org.sonar.api.measures.*;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.*;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.Violation;
+import org.sonar.api.utils.SonarException;
+import org.sonar.api.violations.ViolationQuery;
+import org.sonar.batch.DefaultResourceCreationLock;
+import org.sonar.batch.ProjectTree;
+import org.sonar.batch.ResourceFilters;
+import org.sonar.batch.ViolationFilters;
+
+import java.util.*;
+
+public class DefaultIndex extends SonarIndex {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class);
+
+ private RulesProfile profile;
+ private PersistenceManager persistence;
+ private DefaultResourceCreationLock lock;
+ private MetricFinder metricFinder;
+
+ // filters
+ private ViolationFilters violationFilters;
+ private ResourceFilters resourceFilters;
+
+ // caches
+ private Project currentProject;
+ private Map<Resource, Bucket> buckets = Maps.newHashMap();
+ private Set<Dependency> dependencies = Sets.newHashSet();
+ private Map<Resource, Map<Resource, Dependency>> outgoingDependenciesByResource = Maps.newHashMap();
+ private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newHashMap();
+ private ProjectTree projectTree;
+
+ public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder) {
+ this.persistence = persistence;
+ this.lock = lock;
+ this.projectTree = projectTree;
+ this.metricFinder = metricFinder;
+ }
+
+ public void start() {
+ Project rootProject = projectTree.getRootProject();
+ doStart(rootProject);
+ }
+
+ void doStart(Project rootProject) {
+ Bucket bucket = new Bucket(rootProject);
+ buckets.put(rootProject, bucket);
+ persistence.saveProject(rootProject, null);
+ currentProject = rootProject;
+
+ for (Project project : rootProject.getModules()) {
+ addProject(project);
+ }
+ }
+
+ private void addProject(Project project) {
+ addResource(project);
+ for (Project module : project.getModules()) {
+ addProject(module);
+ }
+ }
+
+ public Project getProject() {
+ return currentProject;
+ }
+
+ public void setCurrentProject(Project project, ResourceFilters resourceFilters, ViolationFilters violationFilters, RulesProfile profile) {
+ this.currentProject = project;
+
+ // the following components depend on the current project, so they need to be reloaded.
+ this.resourceFilters = resourceFilters;
+ this.violationFilters = violationFilters;
+ this.profile = profile;
+ }
+
+ /**
+ * Keep only project stuff
+ */
+ public void clear() {
+ Iterator<Map.Entry<Resource, Bucket>> it = buckets.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<Resource, Bucket> entry = it.next();
+ Resource resource = entry.getKey();
+ if (!ResourceUtils.isSet(resource)) {
+ entry.getValue().clear();
+ it.remove();
+ }
+ }
+
+ Set<Dependency> projectDependencies = getDependenciesBetweenProjects();
+ dependencies.clear();
+ incomingDependenciesByResource.clear();
+ outgoingDependenciesByResource.clear();
+ for (Dependency projectDependency : projectDependencies) {
+ projectDependency.setId(null);
+ registerDependency(projectDependency);
+ }
+
+ lock.unlock();
+ }
+
+ public Measure getMeasure(Resource resource, Metric metric) {
+ Bucket bucket = buckets.get(resource);
+ if (bucket != null) {
+ Measure measure = bucket.getMeasures(MeasuresFilters.metric(metric));
+ if (measure != null) {
+ return persistence.reloadMeasure(measure);
+ }
+ }
+ return null;
+ }
+
+ public <M> M getMeasures(Resource resource, MeasuresFilter<M> filter) {
+ Bucket bucket = buckets.get(resource);
+ if (bucket != null) {
+ // TODO the data measures which are not kept in memory are not reloaded yet. Use getMeasure().
+ return bucket.getMeasures(filter);
+ }
+ return null;
+ }
+
+ /**
+ * the measure is updated if it's already registered.
+ */
+ public Measure addMeasure(Resource resource, Measure measure) {
+ Bucket bucket = checkIndexed(resource);
+ if (bucket != null && !bucket.isExcluded()) {
+ Metric metric = metricFinder.findByKey(measure.getMetricKey());
+ if (metric == null) {
+ throw new SonarException("Unknown metric: " + measure.getMetricKey());
+ }
+ measure.setMetric(metric);
+ bucket.addMeasure(measure);
+
+ if (measure.getPersistenceMode().useDatabase()) {
+ persistence.saveMeasure(resource, measure);
+ }
+ }
+ return measure;
+ }
+
+ //
+ //
+ //
+ // DEPENDENCIES
+ //
+ //
+ //
+
+ public Dependency addDependency(Dependency dependency) {
+ Dependency existingDep = getEdge(dependency.getFrom(), dependency.getTo());
+ if (existingDep != null) {
+ return existingDep;
+ }
+
+ Dependency parentDependency = dependency.getParent();
+ if (parentDependency != null) {
+ addDependency(parentDependency);
+ }
+
+ if (registerDependency(dependency)) {
+ persistence.saveDependency(currentProject, dependency, parentDependency);
+ }
+ return dependency;
+ }
+
+ boolean registerDependency(Dependency dependency) {
+ Bucket fromBucket = doIndex(dependency.getFrom());
+ Bucket toBucket = doIndex(dependency.getTo());
+
+ if (fromBucket != null && !fromBucket.isExcluded() && toBucket != null && !toBucket.isExcluded()) {
+ dependencies.add(dependency);
+ registerOutgoingDependency(dependency);
+ registerIncomingDependency(dependency);
+ return true;
+ }
+ return false;
+ }
+
+ private void registerOutgoingDependency(Dependency dependency) {
+ Map<Resource, Dependency> outgoingDeps = outgoingDependenciesByResource.get(dependency.getFrom());
+ if (outgoingDeps == null) {
+ outgoingDeps = new HashMap<Resource, Dependency>();
+ outgoingDependenciesByResource.put(dependency.getFrom(), outgoingDeps);
+ }
+ outgoingDeps.put(dependency.getTo(), dependency);
+ }
+
+ private void registerIncomingDependency(Dependency dependency) {
+ Map<Resource, Dependency> incomingDeps = incomingDependenciesByResource.get(dependency.getTo());
+ if (incomingDeps == null) {
+ incomingDeps = new HashMap<Resource, Dependency>();
+ incomingDependenciesByResource.put(dependency.getTo(), incomingDeps);
+ }
+ incomingDeps.put(dependency.getFrom(), dependency);
+ }
+
+ public Set<Dependency> getDependencies() {
+ return dependencies;
+ }
+
+ public Dependency getEdge(Resource from, Resource to) {
+ Map<Resource, Dependency> map = outgoingDependenciesByResource.get(from);
+ if (map != null) {
+ return map.get(to);
+ }
+ return null;
+ }
+
+ public boolean hasEdge(Resource from, Resource to) {
+ return getEdge(from, to) != null;
+ }
+
+ public Set<Resource> getVertices() {
+ return buckets.keySet();
+ }
+
+ public Collection<Dependency> getOutgoingEdges(Resource from) {
+ Map<Resource, Dependency> deps = outgoingDependenciesByResource.get(from);
+ if (deps != null) {
+ return deps.values();
+ }
+ return Collections.emptyList();
+ }
+
+ public Collection<Dependency> getIncomingEdges(Resource to) {
+ Map<Resource, Dependency> deps = incomingDependenciesByResource.get(to);
+ if (deps != null) {
+ return deps.values();
+ }
+ return Collections.emptyList();
+ }
+
+ Set<Dependency> getDependenciesBetweenProjects() {
+ Set<Dependency> result = Sets.newLinkedHashSet();
+ for (Dependency dependency : dependencies) {
+ if (ResourceUtils.isSet(dependency.getFrom()) || ResourceUtils.isSet(dependency.getTo())) {
+ result.add(dependency);
+ }
+ }
+ return result;
+ }
+
+ //
+ //
+ //
+ // VIOLATIONS
+ //
+ //
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<Violation> getViolations(ViolationQuery violationQuery) {
+ Resource resource = violationQuery.getResource();
+ if (resource == null) {
+ throw new IllegalArgumentException("A resource must be set on the ViolationQuery in order to search for violations.");
+ }
+ Bucket bucket = buckets.get(resource);
+ if (bucket == null) {
+ return Collections.emptyList();
+ }
+ List<Violation> filteredViolations = Lists.newArrayList();
+ boolean ignoreSwitchedOff = violationQuery.ignoreSwitchedOff();
+ for (Violation violation : bucket.getViolations()) {
+ if ( ignoreSwitchedOff && violation.isSwitchedOff()) {
+ continue;
+ }
+ filteredViolations.add(violation);
+ }
+ return filteredViolations;
+ }
+
+ public void addViolation(Violation violation, boolean force) {
+ Resource resource = violation.getResource();
+ if (resource == null) {
+ violation.setResource(currentProject);
+ } else if (!Scopes.isHigherThanOrEquals(resource, Scopes.FILE)) {
+ throw new IllegalArgumentException("Violations are only supported on files, directories and project");
+ }
+
+ if (violation.getRule() == null) {
+ LOG.warn("Rule is null, ignoring violation {}", violation);
+ return;
+ }
+
+ Bucket bucket = checkIndexed(resource);
+ if (bucket != null && !bucket.isExcluded()) {
+ boolean isIgnored = !force && violationFilters != null && violationFilters.isIgnored(violation);
+ if (!isIgnored) {
+ ActiveRule activeRule = profile.getActiveRule(violation.getRule());
+ if (activeRule == null) {
+ if (currentProject.getReuseExistingRulesConfig()) {
+ violation.setSeverity(violation.getRule().getSeverity());
+ doAddViolation(violation, bucket);
+
+ } else {
+ LoggerFactory.getLogger(getClass()).debug("Rule is not activated, ignoring violation {}", violation);
+ }
+
+ } else {
+ violation.setSeverity(activeRule.getSeverity());
+ doAddViolation(violation, bucket);
+ }
+ }
+ }
+ }
+
+ private void doAddViolation(Violation violation, Bucket bucket) {
+ bucket.addViolation(violation);
+ }
+
+ //
+ //
+ //
+ // LINKS
+ //
+ //
+ //
+
+ public void addLink(ProjectLink link) {
+ persistence.saveLink(currentProject, link);
+ }
+
+ public void deleteLink(String key) {
+ persistence.deleteLink(currentProject, key);
+ }
+
+ //
+ //
+ //
+ // EVENTS
+ //
+ //
+ //
+
+ public List<Event> getEvents(Resource resource) {
+ // currently events are not cached in memory
+ return persistence.getEvents(resource);
+ }
+
+ public void deleteEvent(Event event) {
+ persistence.deleteEvent(event);
+ }
+
+ public Event addEvent(Resource resource, String name, String description, String category, Date date) {
+ Event event = new Event(name, description, category);
+ event.setDate(date);
+ persistence.saveEvent(resource, event);
+ return null;
+ }
+
+ public void setSource(Resource reference, String source) {
+ Bucket bucket = checkIndexed(reference);
+ if (bucket != null && !bucket.isExcluded()) {
+ persistence.setSource(reference, source);
+ }
+ }
+
+ /**
+ * Does nothing if the resource is already registered.
+ */
+ public Resource addResource(Resource resource) {
+ Bucket bucket = doIndex(resource);
+ return bucket != null ? bucket.getResource() : null;
+ }
+
+ public <R extends Resource> R getResource(R reference) {
+ Bucket bucket = buckets.get(reference);
+ if (bucket != null) {
+ return (R) bucket.getResource();
+ }
+ return null;
+ }
+
+ static String createUID(Project project, Resource resource) {
+ String uid = resource.getKey();
+ if (!StringUtils.equals(Scopes.PROJECT, resource.getScope())) {
+ // not a project nor a library
+ uid = new StringBuilder(ResourceModel.KEY_SIZE)
+ .append(project.getKey())
+ .append(':')
+ .append(resource.getKey())
+ .toString();
+ }
+ return uid;
+ }
+
+ private boolean checkExclusion(Resource resource, Bucket parent) {
+ boolean excluded = (parent != null && parent.isExcluded()) || (resourceFilters != null && resourceFilters.isExcluded(resource));
+ resource.setExcluded(excluded);
+ return excluded;
+ }
+
+ public List<Resource> getChildren(Resource resource) {
+ return getChildren(resource, false);
+ }
+
+ public List<Resource> getChildren(Resource resource, boolean acceptExcluded) {
+ List<Resource> children = Lists.newLinkedList();
+ Bucket bucket = getBucket(resource, acceptExcluded);
+ if (bucket != null) {
+ for (Bucket childBucket : bucket.getChildren()) {
+ if (acceptExcluded || !childBucket.isExcluded()) {
+ children.add(childBucket.getResource());
+ }
+ }
+ }
+ return children;
+ }
+
+ public Resource getParent(Resource resource) {
+ Bucket bucket = getBucket(resource, false);
+ if (bucket != null && bucket.getParent() != null) {
+ return bucket.getParent().getResource();
+ }
+ return null;
+ }
+
+ public boolean index(Resource resource) {
+ Bucket bucket = doIndex(resource);
+ return bucket != null && !bucket.isExcluded();
+ }
+
+ private Bucket doIndex(Resource resource) {
+ if (resource.getParent() != null) {
+ doIndex(resource.getParent());
+ }
+ return doIndex(resource, resource.getParent());
+ }
+
+ public boolean index(Resource resource, Resource parentReference) {
+ Bucket bucket = doIndex(resource, parentReference);
+ return bucket != null && !bucket.isExcluded();
+ }
+
+ private Bucket doIndex(Resource resource, Resource parentReference) {
+ Bucket bucket = buckets.get(resource);
+ if (bucket != null) {
+ return bucket;
+ }
+
+ checkLock(resource);
+
+ Resource parent = null;
+ if (!ResourceUtils.isLibrary(resource)) {
+ // a library has no parent
+ parent = (Resource) ObjectUtils.defaultIfNull(parentReference, currentProject);
+ }
+
+ Bucket parentBucket = getBucket(parent, true);
+ if (parentBucket == null && parent != null) {
+ LOG.warn("Resource ignored, parent is not indexed: " + resource);
+ return null;
+ }
+
+ resource.setEffectiveKey(createUID(currentProject, resource));
+ bucket = new Bucket(resource).setParent(parentBucket);
+ buckets.put(resource, bucket);
+
+ boolean excluded = checkExclusion(resource, parentBucket);
+ if (!excluded) {
+ persistence.saveResource(currentProject, resource, (parentBucket != null ? parentBucket.getResource() : null));
+ }
+ return bucket;
+ }
+
+ private void checkLock(Resource resource) {
+ if (lock.isLocked() && !ResourceUtils.isLibrary(resource)) {
+ if (lock.isFailWhenLocked()) {
+ throw new SonarException("Index is locked, resource can not be indexed: " + resource);
+ }
+ }
+ }
+
+ private Bucket checkIndexed(Resource resource) {
+ Bucket bucket = getBucket(resource, true);
+ if (bucket == null) {
+ if (lock.isLocked()) {
+ if (lock.isFailWhenLocked()) {
+ throw new ResourceNotIndexedException(resource);
+ }
+ LOG.warn("Resource will be ignored in next Sonar versions, index is locked: " + resource);
+ }
+ if (Scopes.isDirectory(resource) || Scopes.isFile(resource)) {
+ bucket = doIndex(resource);
+ } else if (!lock.isLocked()) {
+ LOG.warn("Resource will be ignored in next Sonar versions, it must be indexed before adding data: " + resource);
+ }
+ }
+ return bucket;
+ }
+
+ public boolean isExcluded(Resource reference) {
+ Bucket bucket = getBucket(reference, true);
+ return bucket != null && bucket.isExcluded();
+ }
+
+ public boolean isIndexed(Resource reference, boolean acceptExcluded) {
+ return getBucket(reference, acceptExcluded) != null;
+ }
+
+ private Bucket getBucket(Resource resource, boolean acceptExcluded) {
+ Bucket bucket = null;
+ if (resource != null) {
+ bucket = buckets.get(resource);
+ if (!acceptExcluded && bucket != null && bucket.isExcluded()) {
+ bucket = null;
+ }
+ }
+ return bucket;
+ }
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.batch.index;\r
-\r
-import org.sonar.api.database.DatabaseSession;\r
-import org.sonar.api.database.model.RuleFailureModel;\r
-import org.sonar.api.database.model.Snapshot;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.rules.Rule;\r
-import org.sonar.api.rules.RuleFinder;\r
-import org.sonar.api.rules.Violation;\r
-\r
-public final class ViolationPersister {\r
-\r
- private DatabaseSession session;\r
- private ResourcePersister resourcePersister;\r
- private RuleFinder ruleFinder;\r
-\r
- public ViolationPersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) {\r
- this.session = session;\r
- this.resourcePersister = resourcePersister;\r
- this.ruleFinder = ruleFinder;\r
- }\r
-\r
- void saveViolation(Project project, Violation violation) {\r
- saveViolation(project, violation, null, null);\r
- }\r
-\r
- public void saveViolation(Project project, Violation violation, RuleFailureModel pastViolation, String checksum) {\r
- Snapshot snapshot = resourcePersister.saveResource(project, violation.getResource());\r
-\r
- RuleFailureModel model = createModel(violation);\r
- if (pastViolation!=null) {\r
- model.setCreatedAt(pastViolation.getCreatedAt());\r
- model.setPermanentId(pastViolation.getPermanentId());\r
- model.setSwitchedOff(pastViolation.isSwitchedOff());\r
- } else {\r
- // avoid plugins setting date\r
- model.setCreatedAt(snapshot.getCreatedAt());\r
- }\r
- model.setSnapshotId(snapshot.getId());\r
- model.setChecksum(checksum);\r
- session.save(model);\r
-\r
- if (model.getPermanentId()==null) {\r
- model.setPermanentId(model.getId());\r
- session.save(model);\r
- }\r
-\r
- // the following fields can have been changed\r
- violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim)\r
- violation.setCreatedAt(model.getCreatedAt());\r
- violation.setSwitchedOff(model.isSwitchedOff());\r
- }\r
- \r
- public void commit() {\r
- session.commit();\r
- }\r
-\r
- private RuleFailureModel createModel(Violation violation) {\r
- RuleFailureModel model = new RuleFailureModel();\r
- Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey());\r
- model.setRuleId(rule.getId());\r
- model.setPriority(violation.getSeverity());\r
- model.setLine(violation.getLineId());\r
- model.setMessage(violation.getMessage());\r
- model.setCost(violation.getCost());\r
- return model;\r
- }\r
-\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.batch.index;
+
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.model.RuleFailureModel;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Project;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.Violation;
+
+public final class ViolationPersister {
+
+ private DatabaseSession session;
+ private ResourcePersister resourcePersister;
+ private RuleFinder ruleFinder;
+
+ public ViolationPersister(DatabaseSession session, ResourcePersister resourcePersister, RuleFinder ruleFinder) {
+ this.session = session;
+ this.resourcePersister = resourcePersister;
+ this.ruleFinder = ruleFinder;
+ }
+
+ void saveViolation(Project project, Violation violation) {
+ saveViolation(project, violation, null, null);
+ }
+
+ public void saveViolation(Project project, Violation violation, RuleFailureModel pastViolation, String checksum) {
+ Snapshot snapshot = resourcePersister.saveResource(project, violation.getResource());
+
+ RuleFailureModel model = createModel(violation);
+ if (pastViolation!=null) {
+ model.setCreatedAt(pastViolation.getCreatedAt());
+ model.setPermanentId(pastViolation.getPermanentId());
+ model.setSwitchedOff(pastViolation.isSwitchedOff());
+ } else {
+ // avoid plugins setting date
+ model.setCreatedAt(snapshot.getCreatedAt());
+ }
+ model.setSnapshotId(snapshot.getId());
+ model.setChecksum(checksum);
+ session.save(model);
+
+ if (model.getPermanentId()==null) {
+ model.setPermanentId(model.getId());
+ session.save(model);
+ }
+
+ // the following fields can have been changed
+ violation.setMessage(model.getMessage());// the message can be changed in the class RuleFailure (truncate + trim)
+ violation.setCreatedAt(model.getCreatedAt());
+ violation.setSwitchedOff(model.isSwitchedOff());
+ }
+
+ public void commit() {
+ session.commit();
+ }
+
+ private RuleFailureModel createModel(Violation violation) {
+ RuleFailureModel model = new RuleFailureModel();
+ Rule rule = ruleFinder.findByKey(violation.getRule().getRepositoryKey(), violation.getRule().getKey());
+ model.setRuleId(rule.getId());
+ model.setPriority(violation.getSeverity());
+ model.setLine(violation.getLineId());
+ model.setMessage(violation.getMessage());
+ model.setCost(violation.getCost());
+ return model;
+ }
+
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.batch.index;\r
-\r
-import static org.hamcrest.Matchers.nullValue;\r
-import static org.hamcrest.core.Is.is;\r
-import static org.junit.Assert.assertThat;\r
-import static org.mockito.Mockito.mock;\r
-import static org.mockito.Mockito.when;\r
-\r
-import org.apache.commons.lang.StringUtils;\r
-import org.junit.Before;\r
-import org.junit.Test;\r
-import org.sonar.api.batch.ResourceFilter;\r
-import org.sonar.api.measures.CoreMetrics;\r
-import org.sonar.api.measures.Measure;\r
-import org.sonar.api.measures.MeasuresFilters;\r
-import org.sonar.api.measures.MetricFinder;\r
-import org.sonar.api.profiles.RulesProfile;\r
-import org.sonar.api.resources.Directory;\r
-import org.sonar.api.resources.File;\r
-import org.sonar.api.resources.Java;\r
-import org.sonar.api.resources.JavaPackage;\r
-import org.sonar.api.resources.Language;\r
-import org.sonar.api.resources.Library;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.resources.Qualifiers;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.api.rules.Rule;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.api.utils.SonarException;\r
-import org.sonar.api.violations.ViolationQuery;\r
-import org.sonar.batch.DefaultResourceCreationLock;\r
-import org.sonar.batch.ProjectTree;\r
-import org.sonar.batch.ResourceFilters;\r
-import org.sonar.batch.ViolationFilters;\r
-\r
-public class DefaultIndexTest {\r
-\r
- private DefaultIndex index = null;\r
- private DefaultResourceCreationLock lock;\r
- private Rule rule;\r
-\r
- @Before\r
- public void createIndex() {\r
- lock = new DefaultResourceCreationLock();\r
- MetricFinder metricFinder = mock(MetricFinder.class);\r
- when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC);\r
-\r
- index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder);\r
- Project project = new Project("project");\r
-\r
- ResourceFilter filter = new ResourceFilter() {\r
-\r
- public boolean isIgnored(Resource resource) {\r
- return StringUtils.containsIgnoreCase(resource.getKey(), "excluded");\r
- }\r
- };\r
- RulesProfile rulesProfile = RulesProfile.create();\r
- rule = Rule.create("repoKey", "ruleKey", "Rule");\r
- rulesProfile.activateRule(rule, null);\r
- index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[] { filter }), new ViolationFilters(), rulesProfile);\r
- index.doStart(project);\r
- }\r
-\r
- @Test\r
- public void shouldCreateUID() {\r
- Project project = new Project("my_project");\r
- assertThat(DefaultIndex.createUID(project, project), is("my_project"));\r
-\r
- JavaPackage javaPackage = new JavaPackage("org.foo");\r
- assertThat(DefaultIndex.createUID(project, javaPackage), is("my_project:org.foo"));\r
-\r
- Library library = new Library("junit:junit", "4.7");\r
- assertThat(DefaultIndex.createUID(project, library), is("junit:junit"));\r
- }\r
-\r
- @Test\r
- public void shouldIndexParentOfDeprecatedFiles() {\r
- File file = new File("org/foo/Bar.java");\r
- assertThat(index.index(file), is(true));\r
-\r
- Directory reference = new Directory("org/foo");\r
- assertThat(index.getResource(reference).getName(), is("org/foo"));\r
- assertThat(index.isIndexed(reference, true), is(true));\r
- assertThat(index.isExcluded(reference), is(false));\r
- assertThat(index.getChildren(reference).size(), is(1));\r
- assertThat(index.getParent(reference), is(Project.class));\r
- }\r
-\r
- @Test\r
- public void shouldIndexTreeOfResources() {\r
- Directory directory = new Directory("org/foo");\r
- File file = new File("org/foo/Bar.java");\r
- file.setLanguage(Java.INSTANCE);\r
-\r
- assertThat(index.index(directory), is(true));\r
- assertThat(index.index(file, directory), is(true));\r
-\r
- File fileRef = new File("org/foo/Bar.java");\r
- assertThat(index.getResource(fileRef).getKey(), is("org/foo/Bar.java"));\r
- assertThat(index.getResource(fileRef).getLanguage(), is((Language) Java.INSTANCE));\r
- assertThat(index.isIndexed(fileRef, true), is(true));\r
- assertThat(index.isExcluded(fileRef), is(false));\r
- assertThat(index.getChildren(fileRef).size(), is(0));\r
- assertThat(index.getParent(fileRef), is(Directory.class));\r
- }\r
-\r
- @Test\r
- public void shouldIndexLibraryOutsideProjectTree() {\r
- Library lib = new Library("junit", "4.8");\r
- assertThat(index.index(lib), is(true));\r
-\r
- Library reference = new Library("junit", "4.8");\r
- assertThat(index.getResource(reference).getQualifier(), is(Qualifiers.LIBRARY));\r
- assertThat(index.isIndexed(reference, true), is(true));\r
- assertThat(index.isExcluded(reference), is(false));\r
- }\r
-\r
- @Test\r
- public void shouldNotIndexResourceIfParentNotIndexed() {\r
- Directory directory = new Directory("org/other");\r
- File file = new File("org/foo/Bar.java");\r
-\r
- assertThat(index.index(file, directory), is(false));\r
-\r
- File fileRef = new File("org/foo/Bar.java");\r
- assertThat(index.isIndexed(directory, true), is(false));\r
- assertThat(index.isIndexed(fileRef, true), is(false));\r
- assertThat(index.isExcluded(fileRef), is(false));\r
- assertThat(index.getChildren(fileRef).size(), is(0));\r
- assertThat(index.getParent(fileRef), nullValue());\r
- }\r
-\r
- /**\r
- * Only a warning is logged when index is locked.\r
- */\r
- @Test\r
- public void shouldIndexEvenIfLocked() {\r
- lock.lock();\r
-\r
- Directory dir = new Directory("org/foo");\r
- assertThat(index.index(dir), is(true));\r
- assertThat(index.isIndexed(dir, true), is(true));\r
- }\r
-\r
- @Test(expected = SonarException.class)\r
- public void shouldFailIfIndexingAndLocked() {\r
- lock.setFailWhenLocked(true);\r
- lock.lock();\r
-\r
- Directory dir = new Directory("org/foo");\r
- index.index(dir);\r
- }\r
-\r
- @Test\r
- public void shouldBeExcluded() {\r
- File file = new File("org/foo/ExcludedBar.java");\r
- assertThat(index.index(file), is(false));\r
- assertThat(index.isIndexed(file, true), is(true));\r
- assertThat(index.isIndexed(file, false), is(false));\r
- assertThat(index.isExcluded(file), is(true));\r
- }\r
-\r
- @Test\r
- public void shouldIndexResourceWhenAddingMeasure() {\r
- Resource dir = new Directory("org/foo");\r
- index.addMeasure(dir, new Measure("ncloc").setValue(50.0));\r
-\r
- assertThat(index.isIndexed(dir, true), is(true));\r
- assertThat(index.getMeasures(dir, MeasuresFilters.metric("ncloc")).getIntValue(), is(50));\r
- }\r
-\r
- /**\r
- * See http://jira.codehaus.org/browse/SONAR-2107\r
- */\r
- @Test\r
- public void shouldNotFailWhenSavingViolationOnNullRule() {\r
- File file = new File("org/foo/Bar.java");\r
- Violation violation = Violation.create((Rule) null, file);\r
- index.addViolation(violation);\r
-\r
- assertThat(index.getViolations(file).size(), is(0));\r
- }\r
-\r
- @Test\r
- public void testGetViolations() {\r
- File file = new File("org/foo/Bar.java");\r
- Violation violation1 = Violation.create(rule, file);\r
- index.addViolation(violation1);\r
- Violation violation2 = Violation.create(rule, file);\r
- violation2.setSwitchedOff(true);\r
- index.addViolation(violation2);\r
- Violation violation3 = Violation.create(rule, file);\r
- violation3.setSwitchedOff(true);\r
- index.addViolation(violation3);\r
-\r
- assertThat(index.getViolations(file).size(), is(1));\r
- }\r
-\r
- @Test\r
- public void testGetViolationsWithQuery() {\r
- File file = new File("org/foo/Bar.java");\r
- Violation violation1 = Violation.create(rule, file);\r
- index.addViolation(violation1);\r
- Violation violation2 = Violation.create(rule, file);\r
- violation2.setSwitchedOff(true);\r
- index.addViolation(violation2);\r
- Violation violation3 = Violation.create(rule, file);\r
- violation3.setSwitchedOff(true);\r
- index.addViolation(violation3);\r
-\r
- assertThat(index.getViolations(ViolationQuery.create().forResource(file).ignoreSwitchedOff(false)).size(), is(3));\r
- }\r
-\r
- @Test(expected = IllegalArgumentException.class)\r
- public void testGetViolationsWithQueryWithNoResource() {\r
- index.getViolations(ViolationQuery.create());\r
- }\r
-\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.batch.index;
+
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.ResourceFilter;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.MeasuresFilters;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.Directory;
+import org.sonar.api.resources.File;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.JavaPackage;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Library;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.Violation;
+import org.sonar.api.utils.SonarException;
+import org.sonar.api.violations.ViolationQuery;
+import org.sonar.batch.DefaultResourceCreationLock;
+import org.sonar.batch.ProjectTree;
+import org.sonar.batch.ResourceFilters;
+import org.sonar.batch.ViolationFilters;
+
+public class DefaultIndexTest {
+
+ private DefaultIndex index = null;
+ private DefaultResourceCreationLock lock;
+ private Rule rule;
+
+ @Before
+ public void createIndex() {
+ lock = new DefaultResourceCreationLock();
+ MetricFinder metricFinder = mock(MetricFinder.class);
+ when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC);
+
+ index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder);
+ Project project = new Project("project");
+
+ ResourceFilter filter = new ResourceFilter() {
+
+ public boolean isIgnored(Resource resource) {
+ return StringUtils.containsIgnoreCase(resource.getKey(), "excluded");
+ }
+ };
+ RulesProfile rulesProfile = RulesProfile.create();
+ rule = Rule.create("repoKey", "ruleKey", "Rule");
+ rulesProfile.activateRule(rule, null);
+ index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[] { filter }), new ViolationFilters(), rulesProfile);
+ index.doStart(project);
+ }
+
+ @Test
+ public void shouldCreateUID() {
+ Project project = new Project("my_project");
+ assertThat(DefaultIndex.createUID(project, project), is("my_project"));
+
+ JavaPackage javaPackage = new JavaPackage("org.foo");
+ assertThat(DefaultIndex.createUID(project, javaPackage), is("my_project:org.foo"));
+
+ Library library = new Library("junit:junit", "4.7");
+ assertThat(DefaultIndex.createUID(project, library), is("junit:junit"));
+ }
+
+ @Test
+ public void shouldIndexParentOfDeprecatedFiles() {
+ File file = new File("org/foo/Bar.java");
+ assertThat(index.index(file), is(true));
+
+ Directory reference = new Directory("org/foo");
+ assertThat(index.getResource(reference).getName(), is("org/foo"));
+ assertThat(index.isIndexed(reference, true), is(true));
+ assertThat(index.isExcluded(reference), is(false));
+ assertThat(index.getChildren(reference).size(), is(1));
+ assertThat(index.getParent(reference), is(Project.class));
+ }
+
+ @Test
+ public void shouldIndexTreeOfResources() {
+ Directory directory = new Directory("org/foo");
+ File file = new File("org/foo/Bar.java");
+ file.setLanguage(Java.INSTANCE);
+
+ assertThat(index.index(directory), is(true));
+ assertThat(index.index(file, directory), is(true));
+
+ File fileRef = new File("org/foo/Bar.java");
+ assertThat(index.getResource(fileRef).getKey(), is("org/foo/Bar.java"));
+ assertThat(index.getResource(fileRef).getLanguage(), is((Language) Java.INSTANCE));
+ assertThat(index.isIndexed(fileRef, true), is(true));
+ assertThat(index.isExcluded(fileRef), is(false));
+ assertThat(index.getChildren(fileRef).size(), is(0));
+ assertThat(index.getParent(fileRef), is(Directory.class));
+ }
+
+ @Test
+ public void shouldIndexLibraryOutsideProjectTree() {
+ Library lib = new Library("junit", "4.8");
+ assertThat(index.index(lib), is(true));
+
+ Library reference = new Library("junit", "4.8");
+ assertThat(index.getResource(reference).getQualifier(), is(Qualifiers.LIBRARY));
+ assertThat(index.isIndexed(reference, true), is(true));
+ assertThat(index.isExcluded(reference), is(false));
+ }
+
+ @Test
+ public void shouldNotIndexResourceIfParentNotIndexed() {
+ Directory directory = new Directory("org/other");
+ File file = new File("org/foo/Bar.java");
+
+ assertThat(index.index(file, directory), is(false));
+
+ File fileRef = new File("org/foo/Bar.java");
+ assertThat(index.isIndexed(directory, true), is(false));
+ assertThat(index.isIndexed(fileRef, true), is(false));
+ assertThat(index.isExcluded(fileRef), is(false));
+ assertThat(index.getChildren(fileRef).size(), is(0));
+ assertThat(index.getParent(fileRef), nullValue());
+ }
+
+ /**
+ * Only a warning is logged when index is locked.
+ */
+ @Test
+ public void shouldIndexEvenIfLocked() {
+ lock.lock();
+
+ Directory dir = new Directory("org/foo");
+ assertThat(index.index(dir), is(true));
+ assertThat(index.isIndexed(dir, true), is(true));
+ }
+
+ @Test(expected = SonarException.class)
+ public void shouldFailIfIndexingAndLocked() {
+ lock.setFailWhenLocked(true);
+ lock.lock();
+
+ Directory dir = new Directory("org/foo");
+ index.index(dir);
+ }
+
+ @Test
+ public void shouldBeExcluded() {
+ File file = new File("org/foo/ExcludedBar.java");
+ assertThat(index.index(file), is(false));
+ assertThat(index.isIndexed(file, true), is(true));
+ assertThat(index.isIndexed(file, false), is(false));
+ assertThat(index.isExcluded(file), is(true));
+ }
+
+ @Test
+ public void shouldIndexResourceWhenAddingMeasure() {
+ Resource dir = new Directory("org/foo");
+ index.addMeasure(dir, new Measure("ncloc").setValue(50.0));
+
+ assertThat(index.isIndexed(dir, true), is(true));
+ assertThat(index.getMeasures(dir, MeasuresFilters.metric("ncloc")).getIntValue(), is(50));
+ }
+
+ /**
+ * See http://jira.codehaus.org/browse/SONAR-2107
+ */
+ @Test
+ public void shouldNotFailWhenSavingViolationOnNullRule() {
+ File file = new File("org/foo/Bar.java");
+ Violation violation = Violation.create((Rule) null, file);
+ index.addViolation(violation);
+
+ assertThat(index.getViolations(file).size(), is(0));
+ }
+
+ @Test
+ public void testGetViolations() {
+ File file = new File("org/foo/Bar.java");
+ Violation violation1 = Violation.create(rule, file);
+ index.addViolation(violation1);
+ Violation violation2 = Violation.create(rule, file);
+ violation2.setSwitchedOff(true);
+ index.addViolation(violation2);
+ Violation violation3 = Violation.create(rule, file);
+ violation3.setSwitchedOff(true);
+ index.addViolation(violation3);
+
+ assertThat(index.getViolations(file).size(), is(1));
+ }
+
+ @Test
+ public void testGetViolationsWithQuery() {
+ File file = new File("org/foo/Bar.java");
+ Violation violation1 = Violation.create(rule, file);
+ index.addViolation(violation1);
+ Violation violation2 = Violation.create(rule, file);
+ violation2.setSwitchedOff(true);
+ index.addViolation(violation2);
+ Violation violation3 = Violation.create(rule, file);
+ violation3.setSwitchedOff(true);
+ index.addViolation(violation3);
+
+ assertThat(index.getViolations(ViolationQuery.create().forResource(file).ignoreSwitchedOff(false)).size(), is(3));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetViolationsWithQueryWithNoResource() {
+ index.getViolations(ViolationQuery.create());
+ }
+
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.batch.index;\r
-\r
-import org.junit.Before;\r
-import org.junit.Test;\r
-import org.sonar.api.database.model.RuleFailureModel;\r
-import org.sonar.api.database.model.Snapshot;\r
-import org.sonar.api.resources.JavaFile;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.rules.Rule;\r
-import org.sonar.api.rules.RulePriority;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.core.components.DefaultRuleFinder;\r
-import org.sonar.jpa.test.AbstractDbUnitTestCase;\r
-\r
-import static org.mockito.Matchers.anyObject;\r
-import static org.mockito.Matchers.eq;\r
-import static org.mockito.Mockito.mock;\r
-import static org.mockito.Mockito.when;\r
-\r
-public class ViolationPersisterTest extends AbstractDbUnitTestCase {\r
-\r
- private ViolationPersister violationPersister;\r
- private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header");\r
- private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null");\r
- private JavaFile javaFile = new JavaFile("org.foo.Bar");\r
- Project project = new Project("project");\r
-\r
- @Before\r
- public void before() {\r
- setupData("shared");\r
- Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000);\r
- ResourcePersister resourcePersister = mock(ResourcePersister.class);\r
- when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot);\r
- when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot);\r
- violationPersister = new ViolationPersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory()));\r
- }\r
-\r
- @Test\r
- public void shouldSaveViolations() {\r
- Violation violation1a = Violation.create(rule1, javaFile)\r
- .setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6)\r
- .setMessage("the message");\r
- Violation violation1b = Violation.create(rule1, javaFile)\r
- .setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0);\r
- Violation violation2 = Violation.create(rule2, javaFile)\r
- .setSeverity(RulePriority.MINOR);\r
-\r
- violationPersister.saveViolation(project, violation1a);\r
- violationPersister.saveViolation(project, violation1b);\r
- violationPersister.saveViolation(project, violation2);\r
-\r
- checkTables("shouldInsertViolations", "rule_failures");\r
- }\r
-\r
- @Test\r
- public void shouldCopyPermanentIdFromPastViolation() {\r
- RuleFailureModel pastViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1);\r
-\r
- Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message");\r
- violationPersister.saveViolation(project, violation, pastViolation, "line_checksum");\r
-\r
- checkTables("shouldCopyPermanentIdFromPastViolation", "rule_failures");\r
- }\r
-\r
- @Test\r
- public void shouldCopySwitchedOffFromPastViolation() {\r
- RuleFailureModel pastViolation1 = getSession().getSingleResult(RuleFailureModel.class, "id", 1);\r
- Violation violation1 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message");\r
- violationPersister.saveViolation(project, violation1, pastViolation1, "line_checksum");\r
-\r
- RuleFailureModel pastViolation2 = getSession().getSingleResult(RuleFailureModel.class, "id", 2);\r
- Violation violation2 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message");\r
- violationPersister.saveViolation(project, violation2, pastViolation2, "line_checksum");\r
-\r
- checkTables("shouldCopySwitchedOffFromPastViolation", "rule_failures");\r
- }\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.batch.index;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.database.model.RuleFailureModel;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Project;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.Violation;
+import org.sonar.core.components.DefaultRuleFinder;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ViolationPersisterTest extends AbstractDbUnitTestCase {
+
+ private ViolationPersister violationPersister;
+ private Rule rule1 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", "Check Header");
+ private Rule rule2 = Rule.create("checkstyle", "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck", "Equals Avoid Null");
+ private JavaFile javaFile = new JavaFile("org.foo.Bar");
+ Project project = new Project("project");
+
+ @Before
+ public void before() {
+ setupData("shared");
+ Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000);
+ ResourcePersister resourcePersister = mock(ResourcePersister.class);
+ when(resourcePersister.saveResource((Project) anyObject(), eq(javaFile))).thenReturn(snapshot);
+ when(resourcePersister.getSnapshot(javaFile)).thenReturn(snapshot);
+ violationPersister = new ViolationPersister(getSession(), resourcePersister, new DefaultRuleFinder(getSessionFactory()));
+ }
+
+ @Test
+ public void shouldSaveViolations() {
+ Violation violation1a = Violation.create(rule1, javaFile)
+ .setSeverity(RulePriority.CRITICAL).setLineId(20).setCost(55.6)
+ .setMessage("the message");
+ Violation violation1b = Violation.create(rule1, javaFile)
+ .setSeverity(RulePriority.CRITICAL).setLineId(50).setCost(80.0);
+ Violation violation2 = Violation.create(rule2, javaFile)
+ .setSeverity(RulePriority.MINOR);
+
+ violationPersister.saveViolation(project, violation1a);
+ violationPersister.saveViolation(project, violation1b);
+ violationPersister.saveViolation(project, violation2);
+
+ checkTables("shouldInsertViolations", "rule_failures");
+ }
+
+ @Test
+ public void shouldCopyPermanentIdFromPastViolation() {
+ RuleFailureModel pastViolation = getSession().getSingleResult(RuleFailureModel.class, "id", 1);
+
+ Violation violation = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message");
+ violationPersister.saveViolation(project, violation, pastViolation, "line_checksum");
+
+ checkTables("shouldCopyPermanentIdFromPastViolation", "rule_failures");
+ }
+
+ @Test
+ public void shouldCopySwitchedOffFromPastViolation() {
+ RuleFailureModel pastViolation1 = getSession().getSingleResult(RuleFailureModel.class, "id", 1);
+ Violation violation1 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message");
+ violationPersister.saveViolation(project, violation1, pastViolation1, "line_checksum");
+
+ RuleFailureModel pastViolation2 = getSession().getSingleResult(RuleFailureModel.class, "id", 2);
+ Violation violation2 = Violation.create(rule1, javaFile).setSeverity(RulePriority.MAJOR).setMessage("new message");
+ violationPersister.saveViolation(project, violation2, pastViolation2, "line_checksum");
+
+ checkTables("shouldCopySwitchedOffFromPastViolation", "rule_failures");
+ }
+}
-<dataset>\r
-\r
- <rules_categories id="1" name="Efficiency" description="[null]"/>\r
- <rules_categories id="6" name="Usability" description="[null]"/>\r
-\r
- <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"\r
- plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"\r
- plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"\r
- name="Bar" long_name="org.foo.Bar" description="[null]"\r
- enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>\r
-\r
- <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"\r
- scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""\r
- status="U" islast="false" depth="3" />\r
-\r
- <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
-</dataset>\r
+<dataset>
+
+ <rules_categories id="1" name="Efficiency" description="[null]"/>
+ <rules_categories id="6" name="Usability" description="[null]"/>
+
+ <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
+ plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
+ plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"
+ name="Bar" long_name="org.foo.Bar" description="[null]"
+ enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"
+ scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""
+ status="U" islast="false" depth="3" />
+
+ <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+</dataset>
-<dataset>\r
-\r
- <rules_categories id="1" name="Efficiency" description="[null]"/>\r
- <rules_categories id="6" name="Usability" description="[null]"/>\r
-\r
- <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"\r
- plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"\r
- plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"\r
- name="Bar" long_name="org.foo.Bar" description="[null]"\r
- enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>\r
-\r
- <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"\r
- scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""\r
- status="U" islast="false" depth="3" />\r
-\r
- <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
-\r
- <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/>\r
-</dataset>\r
+<dataset>
+
+ <rules_categories id="1" name="Efficiency" description="[null]"/>
+ <rules_categories id="6" name="Usability" description="[null]"/>
+
+ <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
+ plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
+ plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"
+ name="Bar" long_name="org.foo.Bar" description="[null]"
+ enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"
+ scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""
+ status="U" islast="false" depth="3" />
+
+ <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+
+ <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/>
+</dataset>
-<dataset>\r
-\r
- <rules_categories id="1" name="Efficiency" description="[null]"/>\r
- <rules_categories id="6" name="Usability" description="[null]"/>\r
-\r
- <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"\r
- plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"\r
- plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"\r
- name="Bar" long_name="org.foo.Bar" description="[null]"\r
- enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>\r
-\r
- <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"\r
- scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""\r
- status="U" islast="false" depth="3" />\r
-\r
- <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
-\r
- <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/>\r
- <rule_failures switched_off="true" permanent_id="2" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/>\r
-</dataset>\r
+<dataset>
+
+ <rules_categories id="1" name="Efficiency" description="[null]"/>
+ <rules_categories id="6" name="Usability" description="[null]"/>
+
+ <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
+ plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
+ plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"
+ name="Bar" long_name="org.foo.Bar" description="[null]"
+ enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"
+ scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""
+ status="U" islast="false" depth="3" />
+
+ <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+
+ <rule_failures switched_off="false" permanent_id="1" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/>
+ <rule_failures switched_off="true" permanent_id="2" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="2" MESSAGE="new message" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="line_checksum"/>
+</dataset>
-<dataset>\r
- <rules_categories id="1" name="Efficiency" description="[null]"/>\r
- <rules_categories id="6" name="Usability" description="[null]"/>\r
-\r
- <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"\r
- plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"\r
- plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"\r
- cardinality="SINGLE" parent_id="[null]"/>\r
-\r
- <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"\r
- name="Bar" long_name="org.foo.Bar" description="[null]"\r
- enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>\r
-\r
- <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"\r
- scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""\r
- status="U" islast="false" depth="3" />\r
-\r
- <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
- <rule_failures switched_off="false" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>\r
+<dataset>
+ <rules_categories id="1" name="Efficiency" description="[null]"/>
+ <rules_categories id="6" name="Usability" description="[null]"/>
+
+ <rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
+ plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
+ plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" enabled="true"
+ cardinality="SINGLE" parent_id="[null]"/>
+
+ <projects id="200" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar" root_id="[null]"
+ name="Bar" long_name="org.foo.Bar" description="[null]"
+ enabled="true" language="java" copy_resource_id="[null]" profile_id="[null]"/>
+
+ <snapshots period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]" period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]" period5_param="[null]" period5_date="[null]" id="1000" project_id="200" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"
+ scope="FIL" qualifier="CLA" created_at="2008-11-01 13:58:00.00" version="[null]" path=""
+ status="U" islast="false" depth="3" />
+
+ <rule_failures switched_off="false" permanent_id="1" ID="1" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="true" permanent_id="2" ID="2" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="old message" LINE="10" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="false" permanent_id="3" ID="3" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="the message" LINE="20" COST="55.6" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="false" permanent_id="4" ID="4" SNAPSHOT_ID="1000" RULE_ID="30" FAILURE_LEVEL="3" MESSAGE="[null]" LINE="50" COST="80" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
+ <rule_failures switched_off="false" permanent_id="5" ID="5" SNAPSHOT_ID="1000" RULE_ID="31" FAILURE_LEVEL="1" MESSAGE="[null]" LINE="[null]" COST="[null]" created_at="2008-11-01 13:58:00.00" checksum="[null]"/>
</dataset>
\ No newline at end of file
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.jpa.session;\r
-\r
-import org.apache.commons.lang.StringUtils;\r
-import org.sonar.api.database.DatabaseSession;\r
-\r
-import java.util.*;\r
-\r
-import javax.persistence.EntityManager;\r
-import javax.persistence.NonUniqueResultException;\r
-import javax.persistence.PersistenceException;\r
-import javax.persistence.Query;\r
-\r
-public class JpaDatabaseSession extends DatabaseSession {\r
-\r
- private final DatabaseConnector connector;\r
- private EntityManager entityManager = null;\r
- private int index = 0;\r
- private boolean inTransaction = false;\r
-\r
- public JpaDatabaseSession(DatabaseConnector connector) {\r
- this.connector = connector;\r
- }\r
-\r
- /**\r
- * Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling,\r
- * which done in methods of this class.\r
- */\r
- public EntityManager getEntityManager() {\r
- return entityManager;\r
- }\r
-\r
- public void start() {\r
- entityManager = connector.createEntityManager();\r
- index = 0;\r
- }\r
-\r
- public void stop() {\r
- commit();\r
- if (entityManager != null && entityManager.isOpen()) {\r
- entityManager.close();\r
- entityManager = null;\r
- }\r
- }\r
-\r
- public void commit() {\r
- if (entityManager != null && inTransaction) {\r
- if (entityManager.isOpen()) {\r
- if (entityManager.getTransaction().getRollbackOnly()) {\r
- entityManager.getTransaction().rollback();\r
- } else {\r
- entityManager.getTransaction().commit();\r
- }\r
- entityManager.clear();\r
- index = 0;\r
- }\r
- inTransaction = false;\r
- }\r
- }\r
-\r
- public void rollback() {\r
- if (entityManager != null && inTransaction) {\r
- entityManager.getTransaction().rollback();\r
- inTransaction = false;\r
- }\r
- }\r
-\r
- public <T> T save(T model) {\r
- startTransaction();\r
- internalSave(model, true);\r
- return model;\r
- }\r
-\r
- public Object saveWithoutFlush(Object model) {\r
- startTransaction();\r
- internalSave(model, false);\r
- return model;\r
- }\r
-\r
- public boolean contains(Object model) {\r
- startTransaction();\r
- return entityManager.contains(model);\r
- }\r
-\r
- public void save(Object... models) {\r
- startTransaction();\r
- for (Object model : models) {\r
- save(model);\r
- }\r
- }\r
-\r
- private void internalSave(Object model, boolean flushIfNeeded) {\r
- try {\r
- entityManager.persist(model);\r
- } catch (PersistenceException e) {\r
- /*\r
- * See http://jira.codehaus.org/browse/SONAR-2234\r
- * In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here.\r
- */\r
- throw new PersistenceException("Unable to persist : " + model, e);\r
- }\r
- if (flushIfNeeded && (++index % BATCH_SIZE == 0)) {\r
- commit();\r
- }\r
- }\r
-\r
- public Object merge(Object model) {\r
- startTransaction();\r
- return entityManager.merge(model);\r
- }\r
-\r
- public void remove(Object model) {\r
- startTransaction();\r
- entityManager.remove(model);\r
- if (++index % BATCH_SIZE == 0) {\r
- commit();\r
- }\r
- }\r
-\r
- public void removeWithoutFlush(Object model) {\r
- startTransaction();\r
- entityManager.remove(model);\r
- }\r
-\r
- public <T> T reattach(Class<T> entityClass, Object primaryKey) {\r
- startTransaction();\r
- return entityManager.getReference(entityClass, primaryKey);\r
- }\r
-\r
- private void startTransaction() {\r
- if (!inTransaction) {\r
- entityManager.getTransaction().begin();\r
- inTransaction = true;\r
- }\r
- }\r
-\r
- /**\r
- * Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling,\r
- * which done in {@link #getSingleResult(Query, Object)}.\r
- */\r
- public Query createQuery(String hql) {\r
- startTransaction();\r
- return entityManager.createQuery(hql);\r
- }\r
- \r
- @Override\r
- public Query createNativeQuery(String sql) {\r
- startTransaction();\r
- return entityManager.createNativeQuery(sql);\r
- }\r
-\r
- /**\r
- * @return the result or <code>defaultValue</code>, if not found\r
- * @throws NonUniqueResultException if more than one result\r
- */\r
- public <T> T getSingleResult(Query query, T defaultValue) {\r
- /*\r
- * See http://jira.codehaus.org/browse/SONAR-2225\r
- * By default Hibernate throws NonUniqueResultException without meaningful information about context,\r
- * so we improve it here by adding all results in error message.\r
- * Note that in some rare situations we can receive too many results, which may lead to OOME,\r
- * but actually it will mean that database is corrupted as we don't expect more than one result\r
- * and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood.\r
- */\r
- List<T> result = query.getResultList();\r
-\r
- if (result.size() == 1) {\r
- return result.get(0);\r
-\r
- } else if (result.isEmpty()) {\r
- return defaultValue;\r
-\r
- } else {\r
- Set<T> uniqueResult = new HashSet<T>(result);\r
- if (uniqueResult.size() > 1) {\r
- throw new NonUniqueResultException("Expected single result, but got : " + result.toString());\r
- } else {\r
- return uniqueResult.iterator().next();\r
- }\r
- }\r
- }\r
-\r
- public <T> T getEntity(Class<T> entityClass, Object id) {\r
- startTransaction();\r
- return getEntityManager().find(entityClass, id);\r
- }\r
-\r
- /**\r
- * @return the result or <code>null</code>, if not found\r
- * @throws NonUniqueResultException if more than one result\r
- */\r
- public <T> T getSingleResult(Class<T> entityClass, Object... criterias) {\r
- try {\r
- return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null);\r
-\r
- } catch (NonUniqueResultException ex) {\r
- NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName()\r
- + " with criterias : " + StringUtils.join(criterias, ","));\r
- e.initCause(ex);\r
- throw e;\r
- }\r
- }\r
-\r
- public <T> List<T> getResults(Class<T> entityClass, Object... criterias) {\r
- return getQueryForCriterias(entityClass, true, criterias).getResultList();\r
- }\r
-\r
- public <T> List<T> getResults(Class<T> entityClass) {\r
- return getQueryForCriterias(entityClass, false, null).getResultList();\r
- }\r
-\r
- private Query getQueryForCriterias(Class<?> entityClass, boolean raiseError, Object... criterias) {\r
- if (criterias == null && raiseError) {\r
- throw new IllegalStateException("criterias parameter must be provided");\r
- }\r
- startTransaction();\r
- StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o");\r
- if (criterias != null) {\r
- hql.append(" WHERE ");\r
- Map<String, Object> mappedCriterias = new HashMap<String, Object>();\r
- for (int i = 0; i < criterias.length; i += 2) {\r
- mappedCriterias.put((String) criterias[i], criterias[i + 1]);\r
- }\r
- buildCriteriasHQL(hql, mappedCriterias);\r
- Query query = getEntityManager().createQuery(hql.toString());\r
-\r
- for (Map.Entry<String, Object> entry : mappedCriterias.entrySet()) {\r
- query.setParameter(entry.getKey(), entry.getValue());\r
- }\r
- return query;\r
- }\r
- return getEntityManager().createQuery(hql.toString());\r
- }\r
-\r
- private void buildCriteriasHQL(StringBuilder hql, Map<String, Object> mappedCriterias) {\r
- for (Iterator<String> i = mappedCriterias.keySet().iterator(); i.hasNext();) {\r
- String criteria = i.next();\r
- hql.append("o.").append(criteria).append("=:").append(criteria);\r
- if (i.hasNext()) {\r
- hql.append(" AND ");\r
- }\r
- }\r
- }\r
-\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.jpa.session;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.database.DatabaseSession;
+
+import java.util.*;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NonUniqueResultException;
+import javax.persistence.PersistenceException;
+import javax.persistence.Query;
+
+public class JpaDatabaseSession extends DatabaseSession {
+
+ private final DatabaseConnector connector;
+ private EntityManager entityManager = null;
+ private int index = 0;
+ private boolean inTransaction = false;
+
+ public JpaDatabaseSession(DatabaseConnector connector) {
+ this.connector = connector;
+ }
+
+ /**
+ * Note that usage of this method is discouraged, because it allows to construct and execute queries without additional exception handling,
+ * which done in methods of this class.
+ */
+ public EntityManager getEntityManager() {
+ return entityManager;
+ }
+
+ public void start() {
+ entityManager = connector.createEntityManager();
+ index = 0;
+ }
+
+ public void stop() {
+ commit();
+ if (entityManager != null && entityManager.isOpen()) {
+ entityManager.close();
+ entityManager = null;
+ }
+ }
+
+ public void commit() {
+ if (entityManager != null && inTransaction) {
+ if (entityManager.isOpen()) {
+ if (entityManager.getTransaction().getRollbackOnly()) {
+ entityManager.getTransaction().rollback();
+ } else {
+ entityManager.getTransaction().commit();
+ }
+ entityManager.clear();
+ index = 0;
+ }
+ inTransaction = false;
+ }
+ }
+
+ public void rollback() {
+ if (entityManager != null && inTransaction) {
+ entityManager.getTransaction().rollback();
+ inTransaction = false;
+ }
+ }
+
+ public <T> T save(T model) {
+ startTransaction();
+ internalSave(model, true);
+ return model;
+ }
+
+ public Object saveWithoutFlush(Object model) {
+ startTransaction();
+ internalSave(model, false);
+ return model;
+ }
+
+ public boolean contains(Object model) {
+ startTransaction();
+ return entityManager.contains(model);
+ }
+
+ public void save(Object... models) {
+ startTransaction();
+ for (Object model : models) {
+ save(model);
+ }
+ }
+
+ private void internalSave(Object model, boolean flushIfNeeded) {
+ try {
+ entityManager.persist(model);
+ } catch (PersistenceException e) {
+ /*
+ * See http://jira.codehaus.org/browse/SONAR-2234
+ * In some cases Hibernate can throw exceptions without meaningful information about context, so we improve them here.
+ */
+ throw new PersistenceException("Unable to persist : " + model, e);
+ }
+ if (flushIfNeeded && (++index % BATCH_SIZE == 0)) {
+ commit();
+ }
+ }
+
+ public Object merge(Object model) {
+ startTransaction();
+ return entityManager.merge(model);
+ }
+
+ public void remove(Object model) {
+ startTransaction();
+ entityManager.remove(model);
+ if (++index % BATCH_SIZE == 0) {
+ commit();
+ }
+ }
+
+ public void removeWithoutFlush(Object model) {
+ startTransaction();
+ entityManager.remove(model);
+ }
+
+ public <T> T reattach(Class<T> entityClass, Object primaryKey) {
+ startTransaction();
+ return entityManager.getReference(entityClass, primaryKey);
+ }
+
+ private void startTransaction() {
+ if (!inTransaction) {
+ entityManager.getTransaction().begin();
+ inTransaction = true;
+ }
+ }
+
+ /**
+ * Note that not recommended to directly execute {@link Query#getSingleResult()}, because it will bypass exception handling,
+ * which done in {@link #getSingleResult(Query, Object)}.
+ */
+ public Query createQuery(String hql) {
+ startTransaction();
+ return entityManager.createQuery(hql);
+ }
+
+ @Override
+ public Query createNativeQuery(String sql) {
+ startTransaction();
+ return entityManager.createNativeQuery(sql);
+ }
+
+ /**
+ * @return the result or <code>defaultValue</code>, if not found
+ * @throws NonUniqueResultException if more than one result
+ */
+ public <T> T getSingleResult(Query query, T defaultValue) {
+ /*
+ * See http://jira.codehaus.org/browse/SONAR-2225
+ * By default Hibernate throws NonUniqueResultException without meaningful information about context,
+ * so we improve it here by adding all results in error message.
+ * Note that in some rare situations we can receive too many results, which may lead to OOME,
+ * but actually it will mean that database is corrupted as we don't expect more than one result
+ * and in fact org.hibernate.ejb.QueryImpl#getSingleResult() anyway does loading of several results under the hood.
+ */
+ List<T> result = query.getResultList();
+
+ if (result.size() == 1) {
+ return result.get(0);
+
+ } else if (result.isEmpty()) {
+ return defaultValue;
+
+ } else {
+ Set<T> uniqueResult = new HashSet<T>(result);
+ if (uniqueResult.size() > 1) {
+ throw new NonUniqueResultException("Expected single result, but got : " + result.toString());
+ } else {
+ return uniqueResult.iterator().next();
+ }
+ }
+ }
+
+ public <T> T getEntity(Class<T> entityClass, Object id) {
+ startTransaction();
+ return getEntityManager().find(entityClass, id);
+ }
+
+ /**
+ * @return the result or <code>null</code>, if not found
+ * @throws NonUniqueResultException if more than one result
+ */
+ public <T> T getSingleResult(Class<T> entityClass, Object... criterias) {
+ try {
+ return getSingleResult(getQueryForCriterias(entityClass, true, criterias), (T) null);
+
+ } catch (NonUniqueResultException ex) {
+ NonUniqueResultException e = new NonUniqueResultException("Expected single result for entitiy " + entityClass.getSimpleName()
+ + " with criterias : " + StringUtils.join(criterias, ","));
+ e.initCause(ex);
+ throw e;
+ }
+ }
+
+ public <T> List<T> getResults(Class<T> entityClass, Object... criterias) {
+ return getQueryForCriterias(entityClass, true, criterias).getResultList();
+ }
+
+ public <T> List<T> getResults(Class<T> entityClass) {
+ return getQueryForCriterias(entityClass, false, null).getResultList();
+ }
+
+ private Query getQueryForCriterias(Class<?> entityClass, boolean raiseError, Object... criterias) {
+ if (criterias == null && raiseError) {
+ throw new IllegalStateException("criterias parameter must be provided");
+ }
+ startTransaction();
+ StringBuilder hql = new StringBuilder("SELECT o FROM ").append(entityClass.getSimpleName()).append(" o");
+ if (criterias != null) {
+ hql.append(" WHERE ");
+ Map<String, Object> mappedCriterias = new HashMap<String, Object>();
+ for (int i = 0; i < criterias.length; i += 2) {
+ mappedCriterias.put((String) criterias[i], criterias[i + 1]);
+ }
+ buildCriteriasHQL(hql, mappedCriterias);
+ Query query = getEntityManager().createQuery(hql.toString());
+
+ for (Map.Entry<String, Object> entry : mappedCriterias.entrySet()) {
+ query.setParameter(entry.getKey(), entry.getValue());
+ }
+ return query;
+ }
+ return getEntityManager().createQuery(hql.toString());
+ }
+
+ private void buildCriteriasHQL(StringBuilder hql, Map<String, Object> mappedCriterias) {
+ for (Iterator<String> i = mappedCriterias.keySet().iterator(); i.hasNext();) {
+ String criteria = i.next();
+ hql.append("o.").append(criteria).append("=:").append(criteria);
+ if (i.hasNext()) {
+ hql.append(" AND ");
+ }
+ }
+ }
+
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.api.batch;\r
-\r
-import org.sonar.api.design.Dependency;\r
-import org.sonar.api.measures.Measure;\r
-import org.sonar.api.measures.MeasuresFilter;\r
-import org.sonar.api.measures.Metric;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.api.violations.ViolationQuery;\r
-\r
-import java.util.Collection;\r
-import java.util.Date;\r
-import java.util.List;\r
-import java.util.Set;\r
-\r
-/**\r
- * @since 1.10\r
- */\r
-public interface DecoratorContext {\r
-\r
- /**\r
- * @return the project in which the decorator is\r
- */\r
- Project getProject();\r
-\r
- /**\r
- * @return the resource that is currently decorated\r
- */\r
- Resource getResource();\r
-\r
- /**\r
- * Child contexts are read only\r
- */\r
- List<DecoratorContext> getChildren();\r
-\r
- // MEASURES\r
-\r
- /**\r
- * Find a measure for the resource\r
- */\r
- Measure getMeasure(Metric metric);\r
-\r
- /**\r
- * Never return null.\r
- */\r
- <M> M getMeasures(MeasuresFilter<M> filter);\r
-\r
- /**\r
- * Never return null.\r
- */\r
- Collection<Measure> getChildrenMeasures(MeasuresFilter filter);\r
-\r
- /**\r
- * @return the resource children measures for the given metric\r
- */\r
- Collection<Measure> getChildrenMeasures(Metric metric);\r
-\r
- /**\r
- * Add a measure on the current resource. It can not be executed from children contexts.\r
- * \r
- * @return the same context\r
- */\r
- DecoratorContext saveMeasure(Measure measure);\r
-\r
- /**\r
- * Add a measure on the current resource. It can not be executed from children contexts.\r
- * \r
- * @return the current object\r
- */\r
- DecoratorContext saveMeasure(Metric metric, Double value);\r
-\r
- // DEPENDENCIES\r
-\r
- Dependency saveDependency(Dependency dependency);\r
-\r
- Set<Dependency> getDependencies();\r
-\r
- Collection<Dependency> getIncomingDependencies();\r
-\r
- Collection<Dependency> getOutgoingDependencies();\r
-\r
- // RULES\r
-\r
- /**\r
- * Returns the violations that match the {@link ViolationQuery} parameters.\r
- * \r
- * @since 2.8\r
- * @param violationQuery\r
- * the request parameters specified as a {@link ViolationQuery}\r
- * @return the list of violations that match those parameters\r
- */\r
- public abstract List<Violation> getViolations(ViolationQuery violationQuery);\r
-\r
- /**\r
- * Returns all the active (= non switched-off) violations found on the current resource.\r
- * \r
- * @return the list of violations\r
- */\r
- List<Violation> getViolations();\r
-\r
- /**\r
- * Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION.\r
- * \r
- * @since 2.5\r
- * @param force allows to force creation of violation even if it was suppressed by {@link org.sonar.api.rules.ViolationFilter}\r
- */\r
- DecoratorContext saveViolation(Violation violation, boolean force);\r
-\r
- /**\r
- * Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION.\r
- */\r
- DecoratorContext saveViolation(Violation violation);\r
-\r
- // EVENTS\r
-\r
- /**\r
- * @return the list of events associated to the current resource\r
- */\r
- List<Event> getEvents();\r
-\r
- /**\r
- * Creates an event for a given date\r
- * \r
- * @param name the event name\r
- * @param description the event description\r
- * @param category the event category\r
- * @param date the event date\r
- * @return the created event\r
- */\r
- Event createEvent(String name, String description, String category, Date date);\r
-\r
- /**\r
- * Deletes an event\r
- * \r
- * @param event the event to delete\r
- */\r
- void deleteEvent(Event event);\r
-\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.api.batch;
+
+import org.sonar.api.design.Dependency;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.MeasuresFilter;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rules.Violation;
+import org.sonar.api.violations.ViolationQuery;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @since 1.10
+ */
+public interface DecoratorContext {
+
+ /**
+ * @return the project in which the decorator is
+ */
+ Project getProject();
+
+ /**
+ * @return the resource that is currently decorated
+ */
+ Resource getResource();
+
+ /**
+ * Child contexts are read only
+ */
+ List<DecoratorContext> getChildren();
+
+ // MEASURES
+
+ /**
+ * Find a measure for the resource
+ */
+ Measure getMeasure(Metric metric);
+
+ /**
+ * Never return null.
+ */
+ <M> M getMeasures(MeasuresFilter<M> filter);
+
+ /**
+ * Never return null.
+ */
+ Collection<Measure> getChildrenMeasures(MeasuresFilter filter);
+
+ /**
+ * @return the resource children measures for the given metric
+ */
+ Collection<Measure> getChildrenMeasures(Metric metric);
+
+ /**
+ * Add a measure on the current resource. It can not be executed from children contexts.
+ *
+ * @return the same context
+ */
+ DecoratorContext saveMeasure(Measure measure);
+
+ /**
+ * Add a measure on the current resource. It can not be executed from children contexts.
+ *
+ * @return the current object
+ */
+ DecoratorContext saveMeasure(Metric metric, Double value);
+
+ // DEPENDENCIES
+
+ Dependency saveDependency(Dependency dependency);
+
+ Set<Dependency> getDependencies();
+
+ Collection<Dependency> getIncomingDependencies();
+
+ Collection<Dependency> getOutgoingDependencies();
+
+ // RULES
+
+ /**
+ * Returns the violations that match the {@link ViolationQuery} parameters.
+ *
+ * @since 2.8
+ * @param violationQuery
+ * the request parameters specified as a {@link ViolationQuery}
+ * @return the list of violations that match those parameters
+ */
+ public abstract List<Violation> getViolations(ViolationQuery violationQuery);
+
+ /**
+ * Returns all the active (= non switched-off) violations found on the current resource.
+ *
+ * @return the list of violations
+ */
+ List<Violation> getViolations();
+
+ /**
+ * Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION.
+ *
+ * @since 2.5
+ * @param force allows to force creation of violation even if it was suppressed by {@link org.sonar.api.rules.ViolationFilter}
+ */
+ DecoratorContext saveViolation(Violation violation, boolean force);
+
+ /**
+ * Save a coding rule violation. The decorator which calls this method must be depended upon BatchBarriers.END_OF_VIOLATIONS_GENERATION.
+ */
+ DecoratorContext saveViolation(Violation violation);
+
+ // EVENTS
+
+ /**
+ * @return the list of events associated to the current resource
+ */
+ List<Event> getEvents();
+
+ /**
+ * Creates an event for a given date
+ *
+ * @param name the event name
+ * @param description the event description
+ * @param category the event category
+ * @param date the event date
+ * @return the created event
+ */
+ Event createEvent(String name, String description, String category, Date date);
+
+ /**
+ * Deletes an event
+ *
+ * @param event the event to delete
+ */
+ void deleteEvent(Event event);
+
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.api.batch;\r
-\r
-import org.sonar.api.design.Dependency;\r
-import org.sonar.api.measures.Measure;\r
-import org.sonar.api.measures.MeasuresFilter;\r
-import org.sonar.api.measures.Metric;\r
-import org.sonar.api.resources.DuplicatedSourceException;\r
-import org.sonar.api.resources.Project;\r
-import org.sonar.api.resources.ProjectLink;\r
-import org.sonar.api.resources.Resource;\r
-import org.sonar.api.rules.Violation;\r
-import org.sonar.api.violations.ViolationQuery;\r
-import org.sonar.graph.DirectedGraphAccessor;\r
-\r
-import java.util.Collection;\r
-import java.util.Date;\r
-import java.util.List;\r
-import java.util.Set;\r
-\r
-public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Dependency> {\r
-\r
- /**\r
- * Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed.\r
- * If the method resource.getParent() does not return null, then this parent will be indexed too.\r
- *\r
- * @return false if the resource is excluded\r
- * @since 2.6\r
- */\r
- public abstract boolean index(Resource resource);\r
-\r
-\r
- /**\r
- * Indexes a resource. This method does nothing if the resource is already indexed.\r
- *\r
- * @param resource the resource to index. Not nullable\r
- * @param parentReference a reference to the indexed parent. If null, the resource is indexed as a direct child of project.\r
- * @return false if the parent is not indexed or if the resource is excluded\r
- * @since 2.6\r
- */\r
- public abstract boolean index(Resource resource, Resource parentReference);\r
-\r
- /**\r
- * Returns true if the referenced resource is excluded. An excluded resource is not indexed.\r
- * @since 2.6\r
- */\r
- public abstract boolean isExcluded(Resource reference);\r
-\r
- /**\r
- * @since 2.6\r
- */\r
- public abstract boolean isIndexed(Resource reference, boolean acceptExcluded);\r
-\r
- /**\r
- * Search for an indexed resource.\r
- *\r
- * @param reference the resource reference\r
- * @return the indexed resource, null if it's not indexed\r
- * @since 1.10. Generic types since 2.6.\r
- */\r
- public abstract <R extends Resource> R getResource(R reference);\r
-\r
- /**\r
- * @since 2.6\r
- */\r
- public abstract Resource getParent(Resource reference);\r
-\r
- /**\r
- * @since 2.6\r
- */\r
-\r
- public abstract Collection<Resource> getChildren(Resource reference);\r
-\r
- /**\r
- * Save the source code of a file. The file must be have been indexed before.\r
- * Note: the source stream is not closed.\r
- *\r
- * @return false if the resource is excluded or not indexed\r
- * @throws org.sonar.api.resources.DuplicatedSourceException\r
- * if the source has already been set on this resource\r
- */\r
- public abstract void setSource(Resource reference, String source) throws DuplicatedSourceException;\r
-\r
- public abstract Project getProject();\r
-\r
- public final Collection<Resource> getResources() {\r
- return getVertices();\r
- }\r
-\r
- /**\r
- * Indexes the resource.\r
- * @return the indexed resource, even if it's excluded\r
- * @deprecated since 2.6. Use methods index()\r
- */\r
- @Deprecated\r
- public abstract Resource addResource(Resource resource);\r
-\r
- public abstract Measure getMeasure(Resource resource, Metric metric);\r
-\r
- public abstract <M> M getMeasures(Resource resource, MeasuresFilter<M> filter);\r
-\r
- /**\r
- * Returns the violations that match the {@link ViolationQuery} parameters.\r
- * \r
- * @since 2.8\r
- * @param violationQuery\r
- * the request parameters specified as a {@link ViolationQuery}\r
- * @return the list of violations that match those parameters\r
- */\r
- public abstract List<Violation> getViolations(ViolationQuery violationQuery);\r
-\r
- /**\r
- * Returns all the active (= non switched-off) violations found on the given resource. Equivalent to\r
- * {@link #getViolations(ViolationQuery)} called with <code>ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true)</code>\r
- * as a parameter.\r
- * \r
- * @since 2.7\r
- * @param the\r
- * resource on which violations are searched\r
- * @return the list of violations\r
- */\r
- public final List<Violation> getViolations(Resource resource) {\r
- return getViolations(ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true));\r
- }\r
-\r
- /**\r
- * @since 2.5\r
- */\r
- public abstract void addViolation(Violation violation, boolean force);\r
-\r
- public final void addViolation(Violation violation) {\r
- addViolation(violation, false);\r
- }\r
-\r
- /**\r
- * Warning: the resource is automatically indexed for backward-compatibility, but it should be explictly\r
- * indexed before. Next versions will deactivate this automatic indexation.\r
- *\r
- * @throws SonarException if the metric is unknown.\r
- */\r
- public abstract Measure addMeasure(Resource resource, Measure measure);\r
-\r
- public abstract Dependency addDependency(Dependency dependency);\r
-\r
- public abstract Set<Dependency> getDependencies();\r
-\r
- public abstract void addLink(ProjectLink link);\r
-\r
- public abstract void deleteLink(String key);\r
-\r
- public abstract List<Event> getEvents(Resource resource);\r
-\r
- public abstract void deleteEvent(Event event);\r
-\r
- public abstract Event addEvent(Resource resource, String name, String description, String category, Date date);\r
-\r
- public final Collection<Dependency> getOutgoingDependencies(Resource from) {\r
- return getOutgoingEdges(from);\r
- }\r
-\r
- public final Collection<Dependency> getIncomingDependencies(Resource to) {\r
- return getIncomingEdges(to);\r
- }\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.api.batch;
+
+import org.sonar.api.design.Dependency;
+import org.sonar.api.measures.Measure;
+import org.sonar.api.measures.MeasuresFilter;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.DuplicatedSourceException;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.ProjectLink;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rules.Violation;
+import org.sonar.api.violations.ViolationQuery;
+import org.sonar.graph.DirectedGraphAccessor;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Dependency> {
+
+ /**
+ * Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed.
+ * If the method resource.getParent() does not return null, then this parent will be indexed too.
+ *
+ * @return false if the resource is excluded
+ * @since 2.6
+ */
+ public abstract boolean index(Resource resource);
+
+
+ /**
+ * Indexes a resource. This method does nothing if the resource is already indexed.
+ *
+ * @param resource the resource to index. Not nullable
+ * @param parentReference a reference to the indexed parent. If null, the resource is indexed as a direct child of project.
+ * @return false if the parent is not indexed or if the resource is excluded
+ * @since 2.6
+ */
+ public abstract boolean index(Resource resource, Resource parentReference);
+
+ /**
+ * Returns true if the referenced resource is excluded. An excluded resource is not indexed.
+ * @since 2.6
+ */
+ public abstract boolean isExcluded(Resource reference);
+
+ /**
+ * @since 2.6
+ */
+ public abstract boolean isIndexed(Resource reference, boolean acceptExcluded);
+
+ /**
+ * Search for an indexed resource.
+ *
+ * @param reference the resource reference
+ * @return the indexed resource, null if it's not indexed
+ * @since 1.10. Generic types since 2.6.
+ */
+ public abstract <R extends Resource> R getResource(R reference);
+
+ /**
+ * @since 2.6
+ */
+ public abstract Resource getParent(Resource reference);
+
+ /**
+ * @since 2.6
+ */
+
+ public abstract Collection<Resource> getChildren(Resource reference);
+
+ /**
+ * Save the source code of a file. The file must be have been indexed before.
+ * Note: the source stream is not closed.
+ *
+ * @return false if the resource is excluded or not indexed
+ * @throws org.sonar.api.resources.DuplicatedSourceException
+ * if the source has already been set on this resource
+ */
+ public abstract void setSource(Resource reference, String source) throws DuplicatedSourceException;
+
+ public abstract Project getProject();
+
+ public final Collection<Resource> getResources() {
+ return getVertices();
+ }
+
+ /**
+ * Indexes the resource.
+ * @return the indexed resource, even if it's excluded
+ * @deprecated since 2.6. Use methods index()
+ */
+ @Deprecated
+ public abstract Resource addResource(Resource resource);
+
+ public abstract Measure getMeasure(Resource resource, Metric metric);
+
+ public abstract <M> M getMeasures(Resource resource, MeasuresFilter<M> filter);
+
+ /**
+ * Returns the violations that match the {@link ViolationQuery} parameters.
+ *
+ * @since 2.8
+ * @param violationQuery
+ * the request parameters specified as a {@link ViolationQuery}
+ * @return the list of violations that match those parameters
+ */
+ public abstract List<Violation> getViolations(ViolationQuery violationQuery);
+
+ /**
+ * Returns all the active (= non switched-off) violations found on the given resource. Equivalent to
+ * {@link #getViolations(ViolationQuery)} called with <code>ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true)</code>
+ * as a parameter.
+ *
+ * @since 2.7
+ * @param the
+ * resource on which violations are searched
+ * @return the list of violations
+ */
+ public final List<Violation> getViolations(Resource resource) {
+ return getViolations(ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true));
+ }
+
+ /**
+ * @since 2.5
+ */
+ public abstract void addViolation(Violation violation, boolean force);
+
+ public final void addViolation(Violation violation) {
+ addViolation(violation, false);
+ }
+
+ /**
+ * Warning: the resource is automatically indexed for backward-compatibility, but it should be explictly
+ * indexed before. Next versions will deactivate this automatic indexation.
+ *
+ * @throws SonarException if the metric is unknown.
+ */
+ public abstract Measure addMeasure(Resource resource, Measure measure);
+
+ public abstract Dependency addDependency(Dependency dependency);
+
+ public abstract Set<Dependency> getDependencies();
+
+ public abstract void addLink(ProjectLink link);
+
+ public abstract void deleteLink(String key);
+
+ public abstract List<Event> getEvents(Resource resource);
+
+ public abstract void deleteEvent(Event event);
+
+ public abstract Event addEvent(Resource resource, String name, String description, String category, Date date);
+
+ public final Collection<Dependency> getOutgoingDependencies(Resource from) {
+ return getOutgoingEdges(from);
+ }
+
+ public final Collection<Dependency> getIncomingDependencies(Resource to) {
+ return getIncomingEdges(to);
+ }
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.api.database;\r
-\r
-import org.sonar.api.BatchComponent;\r
-\r
-import javax.persistence.EntityManager;\r
-import javax.persistence.Query;\r
-import java.util.List;\r
-\r
-/**\r
- * This component should not accessible from plugin API\r
- *\r
- * @since 1.10\r
- */\r
-public abstract class DatabaseSession implements BatchComponent {\r
-\r
-\r
- // IMPORTANT : this value must be the same than the property\r
- // hibernate.jdbc.batch_size from /META-INF/persistence.xml (module sonar-database)\r
- public static final int BATCH_SIZE = 30;\r
-\r
-\r
- public abstract EntityManager getEntityManager();\r
-\r
- public abstract void start();\r
-\r
- public abstract void stop();\r
-\r
- public abstract void commit();\r
-\r
- public abstract void rollback();\r
-\r
- public abstract <T> T save(T entity);\r
-\r
- public abstract Object saveWithoutFlush(Object entity);\r
-\r
- public abstract boolean contains(Object entity);\r
-\r
- public abstract void save(Object... entities);\r
-\r
- public abstract Object merge(Object entity);\r
-\r
- public abstract void remove(Object entity);\r
-\r
- public abstract void removeWithoutFlush(Object entity);\r
-\r
- public abstract <T> T reattach(Class<T> entityClass, Object primaryKey);\r
-\r
- public abstract Query createQuery(String hql);\r
- \r
- public abstract Query createNativeQuery(String sql);\r
-\r
- public abstract <T> T getSingleResult(Query query, T defaultValue);\r
-\r
- public abstract <T> T getEntity(Class<T> entityClass, Object id);\r
-\r
- public abstract <T> T getSingleResult(Class<T> entityClass, Object... criterias);\r
-\r
- public abstract <T> List<T> getResults(Class<T> entityClass, Object... criterias);\r
-\r
- public abstract <T> List<T> getResults(Class<T> entityClass);\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.api.database;
+
+import org.sonar.api.BatchComponent;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.util.List;
+
+/**
+ * This component should not accessible from plugin API
+ *
+ * @since 1.10
+ */
+public abstract class DatabaseSession implements BatchComponent {
+
+
+ // IMPORTANT : this value must be the same than the property
+ // hibernate.jdbc.batch_size from /META-INF/persistence.xml (module sonar-database)
+ public static final int BATCH_SIZE = 30;
+
+
+ public abstract EntityManager getEntityManager();
+
+ public abstract void start();
+
+ public abstract void stop();
+
+ public abstract void commit();
+
+ public abstract void rollback();
+
+ public abstract <T> T save(T entity);
+
+ public abstract Object saveWithoutFlush(Object entity);
+
+ public abstract boolean contains(Object entity);
+
+ public abstract void save(Object... entities);
+
+ public abstract Object merge(Object entity);
+
+ public abstract void remove(Object entity);
+
+ public abstract void removeWithoutFlush(Object entity);
+
+ public abstract <T> T reattach(Class<T> entityClass, Object primaryKey);
+
+ public abstract Query createQuery(String hql);
+
+ public abstract Query createNativeQuery(String sql);
+
+ public abstract <T> T getSingleResult(Query query, T defaultValue);
+
+ public abstract <T> T getEntity(Class<T> entityClass, Object id);
+
+ public abstract <T> T getSingleResult(Class<T> entityClass, Object... criterias);
+
+ public abstract <T> List<T> getResults(Class<T> entityClass, Object... criterias);
+
+ public abstract <T> List<T> getResults(Class<T> entityClass);
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.api.rules;\r
-\r
-import org.apache.commons.lang.builder.EqualsBuilder;\r
-import org.apache.commons.lang.builder.HashCodeBuilder;\r
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;\r
-import org.sonar.api.resources.Resource;\r
-\r
-import java.util.Date;\r
-\r
-/**\r
- * A class that represents a violation. A violation happens when a resource does not respect a defined rule.\r
- */\r
-public class Violation {\r
-\r
- private Resource resource;\r
- private Rule rule;\r
- private String message;\r
- private RulePriority severity;\r
- private Integer lineId;\r
- private Double cost;\r
- private Date createdAt;\r
- private boolean switchedOff;\r
-\r
- /**\r
- * Creates of a violation from a rule. Will need to define the resource later on\r
- * \r
- * @deprecated since 2.3. Use the factory method create()\r
- */\r
- @Deprecated\r
- public Violation(Rule rule) {\r
- this.rule = rule;\r
- }\r
-\r
- /**\r
- * Creates a fully qualified violation\r
- * \r
- * @param rule\r
- * the rule that has been violated\r
- * @param resource\r
- * the resource the violation should be attached to\r
- * @deprecated since 2.3. Use the factory method create()\r
- */\r
- @Deprecated\r
- public Violation(Rule rule, Resource resource) {\r
- this.resource = resource;\r
- this.rule = rule;\r
- }\r
-\r
- public Resource getResource() {\r
- return resource;\r
- }\r
-\r
- /**\r
- * Sets the resource the violation applies to\r
- * \r
- * @return the current object\r
- */\r
- public Violation setResource(Resource resource) {\r
- this.resource = resource;\r
- return this;\r
- }\r
-\r
- public Rule getRule() {\r
- return rule;\r
- }\r
-\r
- /**\r
- * Sets the rule violated\r
- * \r
- * @return the current object\r
- */\r
- public Violation setRule(Rule rule) {\r
- this.rule = rule;\r
- return this;\r
- }\r
-\r
- public String getMessage() {\r
- return message;\r
- }\r
-\r
- /**\r
- * Sets the violation message\r
- * \r
- * @return the current object\r
- */\r
- public Violation setMessage(String message) {\r
- this.message = message;\r
- return this;\r
- }\r
-\r
- /**\r
- * @see #setLineId(Integer)\r
- */\r
- public Integer getLineId() {\r
- return lineId;\r
- }\r
-\r
- /**\r
- * Sets the violation line. Note that numbering starts from 1.\r
- * \r
- * @return the current object\r
- */\r
- public Violation setLineId(Integer lineId) {\r
- this.lineId = lineId;\r
- return this;\r
- }\r
-\r
- /**\r
- * @since 2.5\r
- */\r
- public RulePriority getSeverity() {\r
- return severity;\r
- }\r
-\r
- /**\r
- * For internal use only.\r
- * \r
- * @since 2.5\r
- */\r
- public Violation setSeverity(RulePriority severity) {\r
- this.severity = severity;\r
- return this;\r
- }\r
-\r
- /**\r
- * @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829\r
- */\r
- @Deprecated\r
- public RulePriority getPriority() {\r
- return severity;\r
- }\r
-\r
- /**\r
- * For internal use only\r
- * \r
- * @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829\r
- */\r
- @Deprecated\r
- public Violation setPriority(RulePriority priority) {\r
- this.severity = priority;\r
- return this;\r
- }\r
-\r
- /**\r
- * @see #setCost(Double)\r
- * @since 2.4\r
- */\r
- public Double getCost() {\r
- return cost;\r
- }\r
-\r
- /**\r
- * The cost to fix a violation can't be precisely computed without this information. Let's take the following example : a rule forbids to\r
- * have methods whose complexity is greater than 10. Without this field "cost", the same violation is created with a method whose\r
- * complexity is 15 and a method whose complexity is 100. If the cost to fix one point of complexity is 0.05h, then 15mn is necessary to\r
- * fix the method whose complexity is 15, and 3h5mn is required to fix the method whose complexity is 100.\r
- * \r
- * @since 2.4\r
- */\r
- public Violation setCost(Double d) {\r
- this.cost = d;\r
- return this;\r
- }\r
-\r
- /**\r
- * @since 2.5\r
- */\r
- public Date getCreatedAt() {\r
- return createdAt;\r
- }\r
-\r
- /**\r
- * For internal use only\r
- * \r
- * @since 2.5\r
- */\r
- public Violation setCreatedAt(Date createdAt) {\r
- this.createdAt = createdAt;\r
- return this;\r
- }\r
-\r
- /**\r
- * Switches off the current violation. This is a kind of "mute", which means the violation exists but won't be counted as an active\r
- * violation (and thus, won't be counted in the total number of violations).\r
- * \r
- * @since 2.8\r
- * @param switchedOff\r
- * if true, the violation is considered OFF\r
- */\r
- public void setSwitchedOff(boolean switchedOff) {\r
- this.switchedOff = switchedOff;\r
- }\r
-\r
- /**\r
- * Tells wether this violation is ON or OFF.\r
- * \r
- * @since 2.8\r
- * @return true if the violation has been switched off\r
- */\r
- public boolean isSwitchedOff() {\r
- return switchedOff;\r
- }\r
-\r
- @Override\r
- public boolean equals(Object obj) {\r
- if ( !(obj instanceof Violation)) {\r
- return false;\r
- }\r
- if (this == obj) {\r
- return true;\r
- }\r
- Violation other = (Violation) obj;\r
- return new EqualsBuilder().append(rule, other.getRule()).append(resource, other.getResource()).isEquals();\r
- }\r
-\r
- @Override\r
- public int hashCode() {\r
- return new HashCodeBuilder(17, 37).append(getRule()).append(getResource()).toHashCode();\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return ReflectionToStringBuilder.toString(this);\r
- }\r
-\r
- public static Violation create(ActiveRule activeRule, Resource resource) {\r
- return new Violation(activeRule.getRule()).setResource(resource);\r
- }\r
-\r
- public static Violation create(Rule rule, Resource resource) {\r
- return new Violation(rule).setResource(resource);\r
- }\r
-\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.api.rules;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.sonar.api.resources.Resource;
+
+import java.util.Date;
+
+/**
+ * A class that represents a violation. A violation happens when a resource does not respect a defined rule.
+ */
+public class Violation {
+
+ private Resource resource;
+ private Rule rule;
+ private String message;
+ private RulePriority severity;
+ private Integer lineId;
+ private Double cost;
+ private Date createdAt;
+ private boolean switchedOff;
+
+ /**
+ * Creates of a violation from a rule. Will need to define the resource later on
+ *
+ * @deprecated since 2.3. Use the factory method create()
+ */
+ @Deprecated
+ public Violation(Rule rule) {
+ this.rule = rule;
+ }
+
+ /**
+ * Creates a fully qualified violation
+ *
+ * @param rule
+ * the rule that has been violated
+ * @param resource
+ * the resource the violation should be attached to
+ * @deprecated since 2.3. Use the factory method create()
+ */
+ @Deprecated
+ public Violation(Rule rule, Resource resource) {
+ this.resource = resource;
+ this.rule = rule;
+ }
+
+ public Resource getResource() {
+ return resource;
+ }
+
+ /**
+ * Sets the resource the violation applies to
+ *
+ * @return the current object
+ */
+ public Violation setResource(Resource resource) {
+ this.resource = resource;
+ return this;
+ }
+
+ public Rule getRule() {
+ return rule;
+ }
+
+ /**
+ * Sets the rule violated
+ *
+ * @return the current object
+ */
+ public Violation setRule(Rule rule) {
+ this.rule = rule;
+ return this;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Sets the violation message
+ *
+ * @return the current object
+ */
+ public Violation setMessage(String message) {
+ this.message = message;
+ return this;
+ }
+
+ /**
+ * @see #setLineId(Integer)
+ */
+ public Integer getLineId() {
+ return lineId;
+ }
+
+ /**
+ * Sets the violation line. Note that numbering starts from 1.
+ *
+ * @return the current object
+ */
+ public Violation setLineId(Integer lineId) {
+ this.lineId = lineId;
+ return this;
+ }
+
+ /**
+ * @since 2.5
+ */
+ public RulePriority getSeverity() {
+ return severity;
+ }
+
+ /**
+ * For internal use only.
+ *
+ * @since 2.5
+ */
+ public Violation setSeverity(RulePriority severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ /**
+ * @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829
+ */
+ @Deprecated
+ public RulePriority getPriority() {
+ return severity;
+ }
+
+ /**
+ * For internal use only
+ *
+ * @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829
+ */
+ @Deprecated
+ public Violation setPriority(RulePriority priority) {
+ this.severity = priority;
+ return this;
+ }
+
+ /**
+ * @see #setCost(Double)
+ * @since 2.4
+ */
+ public Double getCost() {
+ return cost;
+ }
+
+ /**
+ * The cost to fix a violation can't be precisely computed without this information. Let's take the following example : a rule forbids to
+ * have methods whose complexity is greater than 10. Without this field "cost", the same violation is created with a method whose
+ * complexity is 15 and a method whose complexity is 100. If the cost to fix one point of complexity is 0.05h, then 15mn is necessary to
+ * fix the method whose complexity is 15, and 3h5mn is required to fix the method whose complexity is 100.
+ *
+ * @since 2.4
+ */
+ public Violation setCost(Double d) {
+ this.cost = d;
+ return this;
+ }
+
+ /**
+ * @since 2.5
+ */
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ /**
+ * For internal use only
+ *
+ * @since 2.5
+ */
+ public Violation setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ /**
+ * Switches off the current violation. This is a kind of "mute", which means the violation exists but won't be counted as an active
+ * violation (and thus, won't be counted in the total number of violations).
+ *
+ * @since 2.8
+ * @param switchedOff
+ * if true, the violation is considered OFF
+ */
+ public void setSwitchedOff(boolean switchedOff) {
+ this.switchedOff = switchedOff;
+ }
+
+ /**
+ * Tells wether this violation is ON or OFF.
+ *
+ * @since 2.8
+ * @return true if the violation has been switched off
+ */
+ public boolean isSwitchedOff() {
+ return switchedOff;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( !(obj instanceof Violation)) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ Violation other = (Violation) obj;
+ return new EqualsBuilder().append(rule, other.getRule()).append(resource, other.getResource()).isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37).append(getRule()).append(getResource()).toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this);
+ }
+
+ public static Violation create(ActiveRule activeRule, Resource resource) {
+ return new Violation(activeRule.getRule()).setResource(resource);
+ }
+
+ public static Violation create(Rule rule, Resource resource) {
+ return new Violation(rule).setResource(resource);
+ }
+
+}
-/*\r
- * Sonar, open source software quality management tool.\r
- * Copyright (C) 2008-2011 SonarSource\r
- * mailto:contact AT sonarsource DOT com\r
- *\r
- * Sonar is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 3 of the License, or (at your option) any later version.\r
- *\r
- * Sonar is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with Sonar; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
- */\r
-package org.sonar.api.violations;\r
-\r
-import org.sonar.api.resources.Resource;\r
-\r
-/**\r
- * Class that allows to query the Sonar index about violations.\r
- * \r
- * @since 2.8\r
- */\r
-public final class ViolationQuery {\r
-\r
- private boolean ignoreSwitchedOff;\r
- private Resource resource;\r
-\r
- /**\r
- * Use the factory method <code>create()</code>\r
- */\r
- ViolationQuery() {\r
- }\r
-\r
- /**\r
- * Creates a new {@link ViolationQuery} object.\r
- * \r
- * @return the new query\r
- */\r
- public static ViolationQuery create() {\r
- return new ViolationQuery();\r
- }\r
-\r
- /**\r
- * Specifies if the query should returned switched-off violations or not.\r
- * \r
- * @param ignore\r
- * if true, the query will return only active violations.\r
- * @return the current violation query\r
- */\r
- public ViolationQuery ignoreSwitchedOff(boolean ignore) {\r
- this.ignoreSwitchedOff = ignore;\r
- return this;\r
- }\r
-\r
- /**\r
- * Tells if the query should returned switched-off violations or not.\r
- * \r
- * @return\r
- */\r
- public boolean ignoreSwitchedOff() {\r
- return ignoreSwitchedOff;\r
- }\r
-\r
- /**\r
- * Specifies the resource which violations are search from.\r
- * \r
- * @param resource\r
- * the resource\r
- */\r
- public ViolationQuery forResource(Resource resource) {\r
- this.resource = resource;\r
- return this;\r
- }\r
-\r
- /**\r
- * Returns the resource which violations are search from.\r
- * \r
- * @return the resource\r
- */\r
- public Resource getResource() {\r
- return resource;\r
- }\r
-}\r
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * 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.api.violations;
+
+import org.sonar.api.resources.Resource;
+
+/**
+ * Class that allows to query the Sonar index about violations.
+ *
+ * @since 2.8
+ */
+public final class ViolationQuery {
+
+ private boolean ignoreSwitchedOff;
+ private Resource resource;
+
+ /**
+ * Use the factory method <code>create()</code>
+ */
+ ViolationQuery() {
+ }
+
+ /**
+ * Creates a new {@link ViolationQuery} object.
+ *
+ * @return the new query
+ */
+ public static ViolationQuery create() {
+ return new ViolationQuery();
+ }
+
+ /**
+ * Specifies if the query should returned switched-off violations or not.
+ *
+ * @param ignore
+ * if true, the query will return only active violations.
+ * @return the current violation query
+ */
+ public ViolationQuery ignoreSwitchedOff(boolean ignore) {
+ this.ignoreSwitchedOff = ignore;
+ return this;
+ }
+
+ /**
+ * Tells if the query should returned switched-off violations or not.
+ *
+ * @return
+ */
+ public boolean ignoreSwitchedOff() {
+ return ignoreSwitchedOff;
+ }
+
+ /**
+ * Specifies the resource which violations are search from.
+ *
+ * @param resource
+ * the resource
+ */
+ public ViolationQuery forResource(Resource resource) {
+ this.resource = resource;
+ return this;
+ }
+
+ /**
+ * Returns the resource which violations are search from.
+ *
+ * @return the resource
+ */
+ public Resource getResource() {
+ return resource;
+ }
+}
-#\r
-# Sonar, entreprise quality control tool.\r
-# Copyright (C) 2008-2011 SonarSource\r
-# mailto:contact AT sonarsource DOT com\r
-#\r
-# Sonar is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 3 of the License, or (at your option) any later version.\r
-#\r
-# Sonar is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with Sonar; if not, write to the Free Software\r
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
-#\r
-class ResourceController < ApplicationController\r
-\r
- SECTION=Navigation::SECTION_RESOURCE\r
- helper DashboardHelper\r
- \r
- def index\r
- @resource = Project.by_key(params[:id])\r
-\r
- if (@resource && has_role?(:user, @resource))\r
- params[:layout]='false'\r
- @snapshot=@resource.last_snapshot\r
-\r
- load_extensions()\r
-\r
- if @extension\r
- if (@extension.getId()=='violations')\r
- render_violations()\r
- elsif (@extension.getId()=='coverage')\r
- render_coverage()\r
- elsif (@extension.getId()=='source')\r
- render_source()\r
- else\r
- render_extension()\r
- end\r
- else\r
- render_nothing()\r
- end\r
- else\r
- access_denied\r
- end\r
- end\r
-\r
- private\r
-\r
- def load_extensions\r
- @extensions=[]\r
- java_facade.getResourceTabs(@resource.scope, @resource.qualifier, @resource.language).each do |tab|\r
- tab.getUserRoles().each do |role|\r
- if has_role?(role, @resource)\r
- @extensions<<tab\r
- break\r
- end\r
- end\r
- end\r
-\r
- if !params[:tab].blank?\r
- @extension=@extensions.find{|extension| extension.getId()==params[:tab]}\r
-\r
- elsif !params[:metric].blank?\r
- metric=Metric.by_key(params[:metric])\r
- @extension=@extensions.find{|extension| extension.getDefaultTabForMetrics().include?(metric.key)}\r
-\r
- end\r
- @extension=@extensions.find{|extension| extension.isDefaultTab()} if @extension==nil\r
- end\r
-\r
- def load_sources\r
- @period = params[:period].to_i unless params[:period].blank?\r
- @expanded=(params[:expand]=='true')\r
-\r
- if @snapshot.source\r
- source_lines=Java::OrgSonarServerUi::JRubyFacade.new.colorizeCode(@snapshot.source.data, @snapshot.project.language).split("\n")\r
- init_scm()\r
-\r
- @lines=[]\r
- source_lines.each_with_index do |source, index|\r
- line=Line.new(source)\r
- @lines<<line\r
-\r
- line.revision=@revisions_by_line[index+1]\r
- line.author=@authors_by_line[index+1]\r
-\r
- date_string=@dates_by_line[index+1]\r
- line.datetime=(date_string ? Java::OrgSonarApiUtils::DateUtils.parseDateTime(date_string): nil)\r
- end\r
- end\r
- end\r
-\r
- def init_scm\r
- @scm_available=(@snapshot.measure('last_commit_datetimes_by_line')!=nil)\r
- @authors_by_line=load_distribution('authors_by_line')\r
- @revisions_by_line=load_distribution('revisions_by_line')\r
- @dates_by_line=load_distribution('last_commit_datetimes_by_line')\r
- end\r
-\r
- def load_distribution(metric_key)\r
- m=@snapshot.measure(metric_key)\r
- m ? m.data_as_line_distribution() : {}\r
- end\r
-\r
- def render_coverage\r
- load_sources()\r
- @display_coverage=true\r
- @expandable=(@lines!=nil)\r
- if @lines\r
- @hits_by_line=load_distribution('coverage_line_hits_data')\r
- @conditions_by_line=load_distribution('conditions_by_line')\r
- @covered_conditions_by_line=load_distribution('covered_conditions_by_line')\r
-\r
- @hits_by_line.each_pair do |line_id,hits|\r
- line=@lines[line_id-1]\r
- if line\r
- line.hits=hits.to_i\r
- line.conditions=@conditions_by_line[line_id].to_i\r
- line.covered_conditions=@covered_conditions_by_line[line_id].to_i\r
- end\r
- end\r
-\r
- if @snapshot.measure('conditions_by_line').nil?\r
- # TODO remove this code when branch_coverage_hits_data is fully removed from CoreMetrics\r
- deprecated_branches_by_line=load_distribution('branch_coverage_hits_data')\r
- deprecated_branches_by_line.each_pair do |line_id,label|\r
- line=@lines[line_id-1]\r
- if line\r
- line.deprecated_conditions_label=label\r
- end\r
- end\r
- end\r
-\r
- to=(@period ? Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000) : nil)\r
- metric=Metric.by_key(params[:coverage_filter]||params[:metric])\r
- @coverage_filter=(metric ? metric.key : 'coverage')\r
- @filtered=true\r
- if ('lines_to_cover'==@coverage_filter || 'coverage'==@coverage_filter || 'line_coverage'==@coverage_filter ||\r
- 'new_lines_to_cover'==@coverage_filter || 'new_coverage'==@coverage_filter || 'new_line_coverage'==@coverage_filter)\r
- @coverage_filter='lines_to_cover'\r
- filter_lines{|line| line.hits && line.after(to)}\r
-\r
- elsif 'uncovered_lines'==@coverage_filter || 'new_uncovered_lines'==@coverage_filter\r
- @coverage_filter='uncovered_lines'\r
- filter_lines{|line| line.hits && line.hits==0 && line.after(to)}\r
-\r
- elsif 'conditions_to_cover'==@coverage_filter || 'branch_coverage'==@coverage_filter ||\r
- 'new_conditions_to_cover'==@coverage_filter || 'new_branch_coverage'==@coverage_filter\r
- @coverage_filter='conditions_to_cover'\r
- filter_lines{|line| line.conditions && line.conditions>0 && line.after(to)}\r
-\r
- elsif 'uncovered_conditions'==@coverage_filter || 'new_uncovered_conditions'==@coverage_filter\r
- @coverage_filter='uncovered_conditions'\r
- filter_lines{|line| line.conditions && line.covered_conditions && line.covered_conditions<line.conditions && line.after(to)}\r
- end\r
- end\r
- render :action => 'index', :layout => !request.xhr?\r
- end\r
-\r
- \r
- \r
- def render_violations\r
- load_sources()\r
- @display_violations=true\r
- @global_violations=[]\r
- @expandable=(@lines!=nil)\r
- @filtered=!@expanded\r
-\r
- conditions='switched_off is not true AND snapshot_id=?'\r
- values=[@snapshot.id]\r
- unless params[:rule].blank?\r
- severity=Sonar::RulePriority.id(params[:rule])\r
- if severity\r
- conditions += ' AND failure_level=?'\r
- values<<severity\r
- else\r
- rule=Rule.by_key_or_id(params[:rule])\r
- conditions += ' AND rule_id=?'\r
- values<<(rule ? rule.id : -1)\r
- end\r
- end\r
-\r
- if @period\r
- date=@snapshot.period_datetime(@period)\r
- if date\r
- conditions+=' AND created_at>?'\r
- values<<date.advance(:minutes => 1)\r
- else\r
- conditions+=' AND id=-1'\r
- end\r
- end\r
-\r
- RuleFailure.find(:all, :include => ['rule', 'reviews' ], :conditions => [conditions] + values, :order => 'failure_level DESC').each do |violation|\r
- # sorted by severity => from blocker to info\r
- if violation.line && violation.line>0 && @lines\r
- @lines[violation.line-1].add_violation(violation)\r
- else\r
- @global_violations<<violation\r
- end\r
- # if the permanent_id does not exist, set it to the current id\r
- unless violation.permanent_id\r
- violation.permanent_id = violation.id\r
- violation.save\r
- end\r
- end\r
-\r
- if !@expanded && @lines\r
- filter_lines{|line| line.violations?}\r
- end\r
- render :action => 'index', :layout => !request.xhr?\r
- end\r
- \r
- \r
- def render_source\r
- load_sources()\r
- filter_lines_by_date()\r
- render :action => 'index', :layout => !request.xhr?\r
- end\r
-\r
- \r
- def filter_lines_by_date\r
- if @period\r
- @filtered=true\r
- to=Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000)\r
- if to\r
- @lines.each do |line|\r
- line.flag_as_hidden() if !line.after(to)\r
- end\r
- end\r
- end\r
- end\r
-\r
- def filter_lines(&block)\r
- @lines.each_with_index do |line,index|\r
- if yield(line)\r
- for i in index-4...index\r
- @lines[i].flag_as_highlight_context() if i>=0\r
- end\r
- line.flag_as_highlighted()\r
- for i in index+1..index+4\r
- @lines[i].flag_as_highlight_context() if i<@lines.size\r
- end\r
- else\r
- line.flag_as_hidden()\r
- end\r
- end\r
- end\r
-\r
- class Line\r
- attr_accessor :source, :revision, :author, :datetime, :violations, :hits, :conditions, :covered_conditions, :hidden, :highlighted, :deprecated_conditions_label\r
-\r
- def initialize(source)\r
- @source=source\r
- end\r
-\r
- def add_violation(violation)\r
- @violations||=[]\r
- @violations<<violation\r
- @visible=true\r
- end\r
-\r
- def violations?\r
- @violations && @violations.size>0\r
- end\r
-\r
- def violation_severity\r
- if @violations && @violations.size>0\r
- @violations[0].failure_level\r
- else\r
- nil\r
- end\r
- end\r
-\r
- def after(date)\r
- if date && @datetime\r
- @datetime.after(date)\r
- else\r
- true\r
- end\r
- end\r
-\r
- def flag_as_highlighted\r
- @highlighted=true\r
- @hidden=false\r
- end\r
-\r
- def flag_as_highlight_context\r
- # do not force if highlighted has already been set to true\r
- @highlighted=false if @highlighted.nil?\r
- @hidden=false\r
- end\r
-\r
- def flag_as_hidden\r
- # do not force if it has already been flagged as visible\r
- if @hidden.nil?\r
- @hidden=true\r
- @highlighted=false\r
- end\r
- end\r
-\r
- def hidden?\r
- @hidden==true\r
- end\r
-\r
- def highlighted?\r
- # highlighted if the @highlighted has not been set or has been set to true\r
- !hidden? && @highlighted!=false\r
- end\r
-\r
- def deprecated_conditions_label=(label)\r
- if label\r
- @deprecated_conditions_label=label\r
- if label=='0%'\r
- @conditions=2\r
- @covered_conditions=0\r
- elsif label=='100%'\r
- @conditions=2\r
- @covered_conditions=2\r
- else\r
- @conditions=2\r
- @covered_conditions=1\r
- end\r
- end\r
- end\r
- end\r
-\r
- def render_extension()\r
- render :action => 'extension', :layout => !request.xhr?\r
- end\r
-\r
- def render_nothing()\r
- render :action => 'nothing', :layout => !request.xhr?\r
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# 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
+#
+class ResourceController < ApplicationController
+
+ SECTION=Navigation::SECTION_RESOURCE
+ helper DashboardHelper
+
+ def index
+ @resource = Project.by_key(params[:id])
+
+ if (@resource && has_role?(:user, @resource))
+ params[:layout]='false'
+ @snapshot=@resource.last_snapshot
+
+ load_extensions()
+
+ if @extension
+ if (@extension.getId()=='violations')
+ render_violations()
+ elsif (@extension.getId()=='coverage')
+ render_coverage()
+ elsif (@extension.getId()=='source')
+ render_source()
+ else
+ render_extension()
+ end
+ else
+ render_nothing()
+ end
+ else
+ access_denied
+ end
+ end
+
+ private
+
+ def load_extensions
+ @extensions=[]
+ java_facade.getResourceTabs(@resource.scope, @resource.qualifier, @resource.language).each do |tab|
+ tab.getUserRoles().each do |role|
+ if has_role?(role, @resource)
+ @extensions<<tab
+ break
+ end
+ end
+ end
+
+ if !params[:tab].blank?
+ @extension=@extensions.find{|extension| extension.getId()==params[:tab]}
+
+ elsif !params[:metric].blank?
+ metric=Metric.by_key(params[:metric])
+ @extension=@extensions.find{|extension| extension.getDefaultTabForMetrics().include?(metric.key)}
+
+ end
+ @extension=@extensions.find{|extension| extension.isDefaultTab()} if @extension==nil
+ end
+
+ def load_sources
+ @period = params[:period].to_i unless params[:period].blank?
+ @expanded=(params[:expand]=='true')
+
+ if @snapshot.source
+ source_lines=Java::OrgSonarServerUi::JRubyFacade.new.colorizeCode(@snapshot.source.data, @snapshot.project.language).split("\n")
+ init_scm()
+
+ @lines=[]
+ source_lines.each_with_index do |source, index|
+ line=Line.new(source)
+ @lines<<line
+
+ line.revision=@revisions_by_line[index+1]
+ line.author=@authors_by_line[index+1]
+
+ date_string=@dates_by_line[index+1]
+ line.datetime=(date_string ? Java::OrgSonarApiUtils::DateUtils.parseDateTime(date_string): nil)
+ end
+ end
+ end
+
+ def init_scm
+ @scm_available=(@snapshot.measure('last_commit_datetimes_by_line')!=nil)
+ @authors_by_line=load_distribution('authors_by_line')
+ @revisions_by_line=load_distribution('revisions_by_line')
+ @dates_by_line=load_distribution('last_commit_datetimes_by_line')
+ end
+
+ def load_distribution(metric_key)
+ m=@snapshot.measure(metric_key)
+ m ? m.data_as_line_distribution() : {}
+ end
+
+ def render_coverage
+ load_sources()
+ @display_coverage=true
+ @expandable=(@lines!=nil)
+ if @lines
+ @hits_by_line=load_distribution('coverage_line_hits_data')
+ @conditions_by_line=load_distribution('conditions_by_line')
+ @covered_conditions_by_line=load_distribution('covered_conditions_by_line')
+
+ @hits_by_line.each_pair do |line_id,hits|
+ line=@lines[line_id-1]
+ if line
+ line.hits=hits.to_i
+ line.conditions=@conditions_by_line[line_id].to_i
+ line.covered_conditions=@covered_conditions_by_line[line_id].to_i
+ end
+ end
+
+ if @snapshot.measure('conditions_by_line').nil?
+ # TODO remove this code when branch_coverage_hits_data is fully removed from CoreMetrics
+ deprecated_branches_by_line=load_distribution('branch_coverage_hits_data')
+ deprecated_branches_by_line.each_pair do |line_id,label|
+ line=@lines[line_id-1]
+ if line
+ line.deprecated_conditions_label=label
+ end
+ end
+ end
+
+ to=(@period ? Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000) : nil)
+ metric=Metric.by_key(params[:coverage_filter]||params[:metric])
+ @coverage_filter=(metric ? metric.key : 'coverage')
+ @filtered=true
+ if ('lines_to_cover'==@coverage_filter || 'coverage'==@coverage_filter || 'line_coverage'==@coverage_filter ||
+ 'new_lines_to_cover'==@coverage_filter || 'new_coverage'==@coverage_filter || 'new_line_coverage'==@coverage_filter)
+ @coverage_filter='lines_to_cover'
+ filter_lines{|line| line.hits && line.after(to)}
+
+ elsif 'uncovered_lines'==@coverage_filter || 'new_uncovered_lines'==@coverage_filter
+ @coverage_filter='uncovered_lines'
+ filter_lines{|line| line.hits && line.hits==0 && line.after(to)}
+
+ elsif 'conditions_to_cover'==@coverage_filter || 'branch_coverage'==@coverage_filter ||
+ 'new_conditions_to_cover'==@coverage_filter || 'new_branch_coverage'==@coverage_filter
+ @coverage_filter='conditions_to_cover'
+ filter_lines{|line| line.conditions && line.conditions>0 && line.after(to)}
+
+ elsif 'uncovered_conditions'==@coverage_filter || 'new_uncovered_conditions'==@coverage_filter
+ @coverage_filter='uncovered_conditions'
+ filter_lines{|line| line.conditions && line.covered_conditions && line.covered_conditions<line.conditions && line.after(to)}
+ end
+ end
+ render :action => 'index', :layout => !request.xhr?
+ end
+
+
+
+ def render_violations
+ load_sources()
+ @display_violations=true
+ @global_violations=[]
+ @expandable=(@lines!=nil)
+ @filtered=!@expanded
+
+ conditions='switched_off is not true AND snapshot_id=?'
+ values=[@snapshot.id]
+ unless params[:rule].blank?
+ severity=Sonar::RulePriority.id(params[:rule])
+ if severity
+ conditions += ' AND failure_level=?'
+ values<<severity
+ else
+ rule=Rule.by_key_or_id(params[:rule])
+ conditions += ' AND rule_id=?'
+ values<<(rule ? rule.id : -1)
+ end
+ end
+
+ if @period
+ date=@snapshot.period_datetime(@period)
+ if date
+ conditions+=' AND created_at>?'
+ values<<date.advance(:minutes => 1)
+ else
+ conditions+=' AND id=-1'
+ end
+ end
+
+ RuleFailure.find(:all, :include => ['rule', 'reviews' ], :conditions => [conditions] + values, :order => 'failure_level DESC').each do |violation|
+ # sorted by severity => from blocker to info
+ if violation.line && violation.line>0 && @lines
+ @lines[violation.line-1].add_violation(violation)
+ else
+ @global_violations<<violation
+ end
+ # if the permanent_id does not exist, set it to the current id
+ unless violation.permanent_id
+ violation.permanent_id = violation.id
+ violation.save
+ end
+ end
+
+ if !@expanded && @lines
+ filter_lines{|line| line.violations?}
+ end
+ render :action => 'index', :layout => !request.xhr?
+ end
+
+
+ def render_source
+ load_sources()
+ filter_lines_by_date()
+ render :action => 'index', :layout => !request.xhr?
+ end
+
+
+ def filter_lines_by_date
+ if @period
+ @filtered=true
+ to=Java::JavaUtil::Date.new(@snapshot.period_datetime(@period).to_f * 1000)
+ if to
+ @lines.each do |line|
+ line.flag_as_hidden() if !line.after(to)
+ end
+ end
+ end
+ end
+
+ def filter_lines(&block)
+ @lines.each_with_index do |line,index|
+ if yield(line)
+ for i in index-4...index
+ @lines[i].flag_as_highlight_context() if i>=0
+ end
+ line.flag_as_highlighted()
+ for i in index+1..index+4
+ @lines[i].flag_as_highlight_context() if i<@lines.size
+ end
+ else
+ line.flag_as_hidden()
+ end
+ end
+ end
+
+ class Line
+ attr_accessor :source, :revision, :author, :datetime, :violations, :hits, :conditions, :covered_conditions, :hidden, :highlighted, :deprecated_conditions_label
+
+ def initialize(source)
+ @source=source
+ end
+
+ def add_violation(violation)
+ @violations||=[]
+ @violations<<violation
+ @visible=true
+ end
+
+ def violations?
+ @violations && @violations.size>0
+ end
+
+ def violation_severity
+ if @violations && @violations.size>0
+ @violations[0].failure_level
+ else
+ nil
+ end
+ end
+
+ def after(date)
+ if date && @datetime
+ @datetime.after(date)
+ else
+ true
+ end
+ end
+
+ def flag_as_highlighted
+ @highlighted=true
+ @hidden=false
+ end
+
+ def flag_as_highlight_context
+ # do not force if highlighted has already been set to true
+ @highlighted=false if @highlighted.nil?
+ @hidden=false
+ end
+
+ def flag_as_hidden
+ # do not force if it has already been flagged as visible
+ if @hidden.nil?
+ @hidden=true
+ @highlighted=false
+ end
+ end
+
+ def hidden?
+ @hidden==true
+ end
+
+ def highlighted?
+ # highlighted if the @highlighted has not been set or has been set to true
+ !hidden? && @highlighted!=false
+ end
+
+ def deprecated_conditions_label=(label)
+ if label
+ @deprecated_conditions_label=label
+ if label=='0%'
+ @conditions=2
+ @covered_conditions=0
+ elsif label=='100%'
+ @conditions=2
+ @covered_conditions=2
+ else
+ @conditions=2
+ @covered_conditions=1
+ end
+ end
+ end
+ end
+
+ def render_extension()
+ render :action => 'extension', :layout => !request.xhr?
+ end
+
+ def render_nothing()
+ render :action => 'nothing', :layout => !request.xhr?
end
end
\ No newline at end of file
-#\r
-# Sonar, entreprise quality control tool.\r
-# Copyright (C) 2008-2011 SonarSource\r
-# mailto:contact AT sonarsource DOT com\r
-#\r
-# Sonar is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 3 of the License, or (at your option) any later version.\r
-#\r
-# Sonar is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with Sonar; if not, write to the Free Software\r
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
-#\r
-\r
-class ReviewsController < ApplicationController\r
-\r
- SECTION=Navigation::SECTION_HOME\r
-\r
- verify :method => :post, :only => [ :create, :create_comment ], :redirect_to => { :action => :error_not_post }\r
-\r
- def index\r
- init_params\r
-\r
- @reviews = []\r
- unless params.blank?\r
- find_reviews_for_user_query\r
- end\r
- end\r
-\r
- def list\r
- reviews = find_reviews_for_rule_failure params[:rule_failure_permanent_id]\r
- render :partial => "list", :locals => { :reviews => reviews }\r
- end\r
-\r
- def display_violation\r
- violation = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id]\r
- render :partial => "resource/violation", :locals => { :violation => violation }\r
- end\r
-\r
- def form\r
- rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id]\r
- @review = Review.new\r
- @review.rule_failure_permanent_id = rule_failure.permanent_id\r
- @review_comment = ReviewComment.new\r
- @review_comment.review_text = ""\r
- if params[:switch_off]\r
- @review.review_type = "f-positive"\r
- else\r
- @review.review_type = Review.default_type\r
- end\r
- render :partial => "form"\r
- end\r
-\r
- def create\r
- rule_failure = find_last_rule_failure_with_permanent_id params[:review][:rule_failure_permanent_id]\r
- unless has_rights_to_create? rule_failure\r
- render :text => "<b>Cannot create the review</b> : access denied."\r
- return\r
- end\r
-\r
- @review = Review.new(params[:review])\r
- @review.user = current_user\r
- if params[:assign_to_me]\r
- @review.assignee = current_user\r
- end\r
- @review.title = rule_failure.message\r
- @review.status = Review.default_status\r
- @review.severity = Sonar::RulePriority.to_s rule_failure.failure_level\r
- @review.resource = RuleFailure.find( @review.rule_failure_permanent_id, :include => ['snapshot'] ).snapshot.project\r
- @review_comment = ReviewComment.new(params[:review_comment])\r
- @review_comment.user = current_user\r
- @review.review_comments << @review_comment\r
- if @review.valid?\r
- if @review.review_type == "f-positive" \r
- if rule_failure.get_open_review\r
- current_open_review = rule_failure.get_open_review\r
- current_open_review.status = "closed"\r
- current_open_review.save\r
- end\r
- rule_failure.switched_off = true\r
- rule_failure.save\r
- end\r
- @review.save\r
- @violation = rule_failure\r
- end\r
- render "create_result"\r
- end\r
-\r
- def form_comment\r
- @review_comment = ReviewComment.new\r
- @review_comment.user = current_user\r
- @review_comment.review_id = params[:review_id]\r
- @review_comment.review_text = ""\r
- @rule_failure_permanent_id = params[:rule_failure_permanent_id]\r
- if params[:update_comment]\r
- @update_comment = true\r
- @review_comment.review_text = params[:review_text]\r
- end\r
- render :partial => "form_comment"\r
- end\r
-\r
- def create_comment\r
- rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id]\r
- unless has_rights_to_create? rule_failure\r
- render :text => "<b>Cannot create the comment</b> : access denied."\r
- return\r
- end\r
-\r
- @review_comment = ReviewComment.new(params[:review_comment])\r
- @review_comment.user = current_user\r
- @rule_failure_permanent_id = params[:rule_failure_permanent_id]\r
- if @review_comment.valid?\r
- @review_comment.save\r
- # -- TODO : should create a Review#create_comment and put the following logic in it\r
- review = @review_comment.review\r
- review.updated_at = @review_comment.created_at\r
- review.save\r
- # -- End of TODO code --\r
- @violation = rule_failure\r
- end\r
- render "create_comment_result"\r
- end\r
-\r
- def update_comment\r
- review = Review.find params[:review_comment][:review_id]\r
- @review_comment = review.review_comments.last\r
- unless current_user && current_user.id == @review_comment.user_id\r
- render :text => "<b>Cannot modify the comment</b> : access denied."\r
- return\r
- end\r
-\r
- @review_comment.review_text = params[:review_comment][:review_text]\r
- @review_comment.created_at = DateTime.now\r
- @rule_failure_permanent_id = params[:rule_failure_permanent_id]\r
- if @review_comment.valid?\r
- @review_comment.save\r
- review.updated_at = @review_comment.updated_at\r
- review.save\r
- @violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id\r
- end\r
- render "create_comment_result"\r
- end\r
- \r
- def form_assign\r
- @user_options = add_all_users []\r
- @review_id = params[:review_id]\r
- @rule_failure_permanent_id = params[:rule_failure_permanent_id]\r
- render :partial => "form_assign"\r
- end\r
- \r
- def assign\r
- review = Review.find params[:review_id]\r
- unless current_user\r
- render :text => "<b>Cannot edit the review</b> : access denied."\r
- return\r
- end\r
- \r
- review.assignee = User.find params[:assignee_id]\r
- review.save\r
- violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id\r
- render :partial => "resource/violation", :locals => { :violation => violation }\r
- end\r
- \r
- def close_review\r
- review = Review.find params[:review_id]\r
- unless current_user\r
- render :text => "<b>Cannot edit the review</b> : access denied."\r
- return\r
- end\r
- \r
- review.status = "closed"\r
- review.save\r
- violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id\r
- render :partial => "resource/violation", :locals => { :violation => violation }\r
- end\r
-\r
- ## -------------- PRIVATE -------------- ##\r
- private\r
-\r
- def init_params\r
- @user_names = [["Any", ""]]\r
- default_user = [""]\r
- if current_user\r
- default_user = [current_user.id]\r
- end\r
- add_all_users @user_names\r
- @review_authors = filter_any(params[:review_authors]) || default_user\r
- @comment_authors = filter_any(params[:comment_authors]) || default_user\r
- @severities = filter_any(params[:severities]) || [""]\r
- @statuses = filter_any(params[:statuses]) || ["open"]\r
- end\r
- \r
- def add_all_users ( user_options )\r
- User.find( :all ).each do |user|\r
- userName = user.name\r
- if current_user.id == user.id\r
- userName = "Me (" + user.name + ")"\r
- end\r
- user_options << [userName, user.id.to_s]\r
- end\r
- return user_options\r
- end\r
-\r
- def filter_any(array)\r
- if array && array.size>1 && array.include?("")\r
- array=[""]\r
- end\r
- array\r
- end\r
-\r
- def find_reviews_for_user_query\r
- conditions=[]\r
- values={}\r
-\r
- unless @statuses == [""]\r
- conditions << "reviews.status in (:statuses)"\r
- values[:statuses]=@statuses\r
- end\r
- unless @severities == [""]\r
- conditions << "reviews.severity in (:severities)"\r
- values[:severities]=@severities\r
- end\r
- unless @review_authors == [""]\r
- conditions << "reviews.user_id in (:review_authors)"\r
- values[:review_authors]=@review_authors\r
- end\r
- unless @comment_authors == [""]\r
- conditions << "review_comments.user_id in (:comment_authors)"\r
- values[:comment_authors]=@comment_authors\r
- end\r
-\r
- @reviews = Review.find( :all, :order => "created_at DESC", :joins => :review_comments, :conditions => [ conditions.join(" AND "), values] ).uniq\r
- end\r
-\r
- def find_reviews_for_rule_failure ( rule_failure_permanent_id )\r
- return Review.find :all, :conditions => ['rule_failure_permanent_id=?', rule_failure_permanent_id]\r
- end\r
-\r
- def find_last_rule_failure_with_permanent_id ( rule_failure_permanent_id )\r
- return RuleFailure.last( :all, :conditions => [ "permanent_id = ?", rule_failure_permanent_id ], :include => ['snapshot'] )\r
- end\r
-\r
- def has_rights_to_create? ( rule_failure )\r
- return false unless current_user\r
- \r
- project = rule_failure.snapshot.root_project\r
- unless has_role?(:user, project)\r
- return false\r
- end\r
- return true\r
- end\r
-\r
- def error_not_post\r
- render :text => "Create actions must use POST method."\r
- end\r
-\r
-end\r
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# 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
+#
+
+class ReviewsController < ApplicationController
+
+ SECTION=Navigation::SECTION_HOME
+
+ verify :method => :post, :only => [ :create, :create_comment ], :redirect_to => { :action => :error_not_post }
+
+ def index
+ init_params
+
+ @reviews = []
+ unless params.blank?
+ find_reviews_for_user_query
+ end
+ end
+
+ def list
+ reviews = find_reviews_for_rule_failure params[:rule_failure_permanent_id]
+ render :partial => "list", :locals => { :reviews => reviews }
+ end
+
+ def display_violation
+ violation = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id]
+ render :partial => "resource/violation", :locals => { :violation => violation }
+ end
+
+ def form
+ rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id]
+ @review = Review.new
+ @review.rule_failure_permanent_id = rule_failure.permanent_id
+ @review_comment = ReviewComment.new
+ @review_comment.review_text = ""
+ if params[:switch_off]
+ @review.review_type = "f-positive"
+ else
+ @review.review_type = Review.default_type
+ end
+ render :partial => "form"
+ end
+
+ def create
+ rule_failure = find_last_rule_failure_with_permanent_id params[:review][:rule_failure_permanent_id]
+ unless has_rights_to_create? rule_failure
+ render :text => "<b>Cannot create the review</b> : access denied."
+ return
+ end
+
+ @review = Review.new(params[:review])
+ @review.user = current_user
+ if params[:assign_to_me]
+ @review.assignee = current_user
+ end
+ @review.title = rule_failure.message
+ @review.status = Review.default_status
+ @review.severity = Sonar::RulePriority.to_s rule_failure.failure_level
+ @review.resource = RuleFailure.find( @review.rule_failure_permanent_id, :include => ['snapshot'] ).snapshot.project
+ @review_comment = ReviewComment.new(params[:review_comment])
+ @review_comment.user = current_user
+ @review.review_comments << @review_comment
+ if @review.valid?
+ if @review.review_type == "f-positive"
+ if rule_failure.get_open_review
+ current_open_review = rule_failure.get_open_review
+ current_open_review.status = "closed"
+ current_open_review.save
+ end
+ rule_failure.switched_off = true
+ rule_failure.save
+ end
+ @review.save
+ @violation = rule_failure
+ end
+ render "create_result"
+ end
+
+ def form_comment
+ @review_comment = ReviewComment.new
+ @review_comment.user = current_user
+ @review_comment.review_id = params[:review_id]
+ @review_comment.review_text = ""
+ @rule_failure_permanent_id = params[:rule_failure_permanent_id]
+ if params[:update_comment]
+ @update_comment = true
+ @review_comment.review_text = params[:review_text]
+ end
+ render :partial => "form_comment"
+ end
+
+ def create_comment
+ rule_failure = find_last_rule_failure_with_permanent_id params[:rule_failure_permanent_id]
+ unless has_rights_to_create? rule_failure
+ render :text => "<b>Cannot create the comment</b> : access denied."
+ return
+ end
+
+ @review_comment = ReviewComment.new(params[:review_comment])
+ @review_comment.user = current_user
+ @rule_failure_permanent_id = params[:rule_failure_permanent_id]
+ if @review_comment.valid?
+ @review_comment.save
+ # -- TODO : should create a Review#create_comment and put the following logic in it
+ review = @review_comment.review
+ review.updated_at = @review_comment.created_at
+ review.save
+ # -- End of TODO code --
+ @violation = rule_failure
+ end
+ render "create_comment_result"
+ end
+
+ def update_comment
+ review = Review.find params[:review_comment][:review_id]
+ @review_comment = review.review_comments.last
+ unless current_user && current_user.id == @review_comment.user_id
+ render :text => "<b>Cannot modify the comment</b> : access denied."
+ return
+ end
+
+ @review_comment.review_text = params[:review_comment][:review_text]
+ @review_comment.created_at = DateTime.now
+ @rule_failure_permanent_id = params[:rule_failure_permanent_id]
+ if @review_comment.valid?
+ @review_comment.save
+ review.updated_at = @review_comment.updated_at
+ review.save
+ @violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id
+ end
+ render "create_comment_result"
+ end
+
+ def form_assign
+ @user_options = add_all_users []
+ @review_id = params[:review_id]
+ @rule_failure_permanent_id = params[:rule_failure_permanent_id]
+ render :partial => "form_assign"
+ end
+
+ def assign
+ review = Review.find params[:review_id]
+ unless current_user
+ render :text => "<b>Cannot edit the review</b> : access denied."
+ return
+ end
+
+ review.assignee = User.find params[:assignee_id]
+ review.save
+ violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id
+ render :partial => "resource/violation", :locals => { :violation => violation }
+ end
+
+ def close_review
+ review = Review.find params[:review_id]
+ unless current_user
+ render :text => "<b>Cannot edit the review</b> : access denied."
+ return
+ end
+
+ review.status = "closed"
+ review.save
+ violation = find_last_rule_failure_with_permanent_id review.rule_failure_permanent_id
+ render :partial => "resource/violation", :locals => { :violation => violation }
+ end
+
+ ## -------------- PRIVATE -------------- ##
+ private
+
+ def init_params
+ @user_names = [["Any", ""]]
+ default_user = [""]
+ if current_user
+ default_user = [current_user.id]
+ end
+ add_all_users @user_names
+ @review_authors = filter_any(params[:review_authors]) || default_user
+ @comment_authors = filter_any(params[:comment_authors]) || default_user
+ @severities = filter_any(params[:severities]) || [""]
+ @statuses = filter_any(params[:statuses]) || ["open"]
+ end
+
+ def add_all_users ( user_options )
+ User.find( :all ).each do |user|
+ userName = user.name
+ if current_user.id == user.id
+ userName = "Me (" + user.name + ")"
+ end
+ user_options << [userName, user.id.to_s]
+ end
+ return user_options
+ end
+
+ def filter_any(array)
+ if array && array.size>1 && array.include?("")
+ array=[""]
+ end
+ array
+ end
+
+ def find_reviews_for_user_query
+ conditions=[]
+ values={}
+
+ unless @statuses == [""]
+ conditions << "reviews.status in (:statuses)"
+ values[:statuses]=@statuses
+ end
+ unless @severities == [""]
+ conditions << "reviews.severity in (:severities)"
+ values[:severities]=@severities
+ end
+ unless @review_authors == [""]
+ conditions << "reviews.user_id in (:review_authors)"
+ values[:review_authors]=@review_authors
+ end
+ unless @comment_authors == [""]
+ conditions << "review_comments.user_id in (:comment_authors)"
+ values[:comment_authors]=@comment_authors
+ end
+
+ @reviews = Review.find( :all, :order => "created_at DESC", :joins => :review_comments, :conditions => [ conditions.join(" AND "), values] ).uniq
+ end
+
+ def find_reviews_for_rule_failure ( rule_failure_permanent_id )
+ return Review.find :all, :conditions => ['rule_failure_permanent_id=?', rule_failure_permanent_id]
+ end
+
+ def find_last_rule_failure_with_permanent_id ( rule_failure_permanent_id )
+ return RuleFailure.last( :all, :conditions => [ "permanent_id = ?", rule_failure_permanent_id ], :include => ['snapshot'] )
+ end
+
+ def has_rights_to_create? ( rule_failure )
+ return false unless current_user
+
+ project = rule_failure.snapshot.root_project
+ unless has_role?(:user, project)
+ return false
+ end
+ return true
+ end
+
+ def error_not_post
+ render :text => "Create actions must use POST method."
+ end
+
+end
-#\r
-# Sonar, entreprise quality control tool.\r
-# Copyright (C) 2008-2011 SonarSource\r
-# mailto:contact AT sonarsource DOT com\r
-#\r
-# Sonar is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 3 of the License, or (at your option) any later version.\r
-#\r
-# Sonar is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with Sonar; if not, write to the Free Software\r
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
-#\r
-class Review < ActiveRecord::Base\r
- belongs_to :user\r
- belongs_to :assignee, :class_name => "User", :foreign_key => "assignee_id"\r
- belongs_to :resource, :class_name => "Project", :foreign_key => "resource_id"\r
- has_many :review_comments, :order => "created_at", :dependent => :destroy\r
- validates_presence_of :user, :message => "can't be empty"\r
- validates_presence_of :title, :message => "can't be empty"\r
- validates_presence_of :review_type, :message => "can't be empty"\r
- validates_presence_of :status, :message => "can't be empty"\r
-\r
- SEVERITY_INFO = "INFO"\r
- SEVERITY_MINOR = "MINOR"\r
- SEVERITY_MAJOR = "MAJOR"\r
- SEVERITY_CRITICAL = "CRITICAL"\r
- SEVERITY_BLOCKER = "BLOCKER"\r
- \r
- TYPE_COMMENTS = "comments"\r
- TYPE_FALSE_POSITIVE = "f-positive"\r
- \r
- STATUS_OPEN = "open"\r
- STATUS_CLOSED = "closed"\r
-\r
-\r
- def self.default_severity\r
- return SEVERITY_MAJOR\r
- end\r
- \r
- def self.default_type\r
- return TYPE_COMMENTS\r
- end\r
-\r
- def self.default_status\r
- return STATUS_OPEN\r
- end\r
- \r
- def self.severity_options\r
- severity_ops = []\r
- severity_ops << ["Info", SEVERITY_INFO]\r
- severity_ops << ["Minor", SEVERITY_MINOR]\r
- severity_ops << ["Major", SEVERITY_MAJOR]\r
- severity_ops << ["Critical", SEVERITY_CRITICAL]\r
- severity_ops << ["Blocker", SEVERITY_BLOCKER]\r
- return severity_ops\r
- end\r
- \r
- def self.status_options\r
- status_ops = []\r
- status_ops << ["Open", STATUS_OPEN]\r
- status_ops << ["Closed", STATUS_CLOSED]\r
- return status_ops\r
- end\r
-\r
-end\r
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# 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
+#
+class Review < ActiveRecord::Base
+ belongs_to :user
+ belongs_to :assignee, :class_name => "User", :foreign_key => "assignee_id"
+ belongs_to :resource, :class_name => "Project", :foreign_key => "resource_id"
+ has_many :review_comments, :order => "created_at", :dependent => :destroy
+ validates_presence_of :user, :message => "can't be empty"
+ validates_presence_of :title, :message => "can't be empty"
+ validates_presence_of :review_type, :message => "can't be empty"
+ validates_presence_of :status, :message => "can't be empty"
+
+ SEVERITY_INFO = "INFO"
+ SEVERITY_MINOR = "MINOR"
+ SEVERITY_MAJOR = "MAJOR"
+ SEVERITY_CRITICAL = "CRITICAL"
+ SEVERITY_BLOCKER = "BLOCKER"
+
+ TYPE_COMMENTS = "comments"
+ TYPE_FALSE_POSITIVE = "f-positive"
+
+ STATUS_OPEN = "open"
+ STATUS_CLOSED = "closed"
+
+
+ def self.default_severity
+ return SEVERITY_MAJOR
+ end
+
+ def self.default_type
+ return TYPE_COMMENTS
+ end
+
+ def self.default_status
+ return STATUS_OPEN
+ end
+
+ def self.severity_options
+ severity_ops = []
+ severity_ops << ["Info", SEVERITY_INFO]
+ severity_ops << ["Minor", SEVERITY_MINOR]
+ severity_ops << ["Major", SEVERITY_MAJOR]
+ severity_ops << ["Critical", SEVERITY_CRITICAL]
+ severity_ops << ["Blocker", SEVERITY_BLOCKER]
+ return severity_ops
+ end
+
+ def self.status_options
+ status_ops = []
+ status_ops << ["Open", STATUS_OPEN]
+ status_ops << ["Closed", STATUS_CLOSED]
+ return status_ops
+ end
+
+end
-#\r
-# Sonar, entreprise quality control tool.\r
-# Copyright (C) 2008-2011 SonarSource\r
-# mailto:contact AT sonarsource DOT com\r
-#\r
-# Sonar is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 3 of the License, or (at your option) any later version.\r
-#\r
-# Sonar is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with {library}; if not, write to the Free Software\r
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
-#\r
-\r
-class RuleFailure < ActiveRecord::Base\r
-\r
- belongs_to :rule\r
- belongs_to :snapshot\r
- has_many :reviews, :primary_key => "permanent_id", :foreign_key => "rule_failure_permanent_id", :order => "created_at"\r
-\r
- def get_open_review\r
- reviews.each do |review|\r
- if review.status == "open"\r
- return review\r
- end\r
- end\r
- return nil\r
- end\r
- \r
- def to_hash_json\r
- json = {}\r
- json['message'] = message\r
- json['line'] = line if line\r
- json['priority'] = Sonar::RulePriority.to_s(failure_level).upcase\r
- if created_at\r
- json['createdAt'] = format_datetime(created_at)\r
- end\r
- json['rule'] = {\r
- :key => rule.key,\r
- :name => rule.name\r
- }\r
- json['resource'] = {\r
- :key => snapshot.project.key,\r
- :name => snapshot.project.name,\r
- :scope => snapshot.project.scope,\r
- :qualifier => snapshot.project.qualifier,\r
- :language => snapshot.project.language\r
- }\r
- json\r
- end\r
-\r
- def to_xml(xml=Builder::XmlMarkup.new(:indent => 0))\r
- xml.violation do\r
- xml.message(message)\r
- xml.line(line) if line\r
- xml.priority(Sonar::RulePriority.to_s(failure_level))\r
- if created_at\r
- xml.createdAt(format_datetime(created_at))\r
- end\r
- xml.rule do\r
- xml.key(rule.key)\r
- xml.name(rule.name)\r
- end\r
- xml.resource do\r
- xml.key(snapshot.project.key)\r
- xml.name(snapshot.project.name)\r
- xml.scope(snapshot.project.scope)\r
- xml.qualifier(snapshot.project.qualifier)\r
- xml.language(snapshot.project.language)\r
- end\r
- end\r
- end\r
-\r
- def format_datetime(datetime)\r
- datetime.strftime("%Y-%m-%dT%H:%M:%S%z")\r
- end\r
-\r
-end\r
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# 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 {library}; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+
+class RuleFailure < ActiveRecord::Base
+
+ belongs_to :rule
+ belongs_to :snapshot
+ has_many :reviews, :primary_key => "permanent_id", :foreign_key => "rule_failure_permanent_id", :order => "created_at"
+
+ def get_open_review
+ reviews.each do |review|
+ if review.status == "open"
+ return review
+ end
+ end
+ return nil
+ end
+
+ def to_hash_json
+ json = {}
+ json['message'] = message
+ json['line'] = line if line
+ json['priority'] = Sonar::RulePriority.to_s(failure_level).upcase
+ if created_at
+ json['createdAt'] = format_datetime(created_at)
+ end
+ json['rule'] = {
+ :key => rule.key,
+ :name => rule.name
+ }
+ json['resource'] = {
+ :key => snapshot.project.key,
+ :name => snapshot.project.name,
+ :scope => snapshot.project.scope,
+ :qualifier => snapshot.project.qualifier,
+ :language => snapshot.project.language
+ }
+ json
+ end
+
+ def to_xml(xml=Builder::XmlMarkup.new(:indent => 0))
+ xml.violation do
+ xml.message(message)
+ xml.line(line) if line
+ xml.priority(Sonar::RulePriority.to_s(failure_level))
+ if created_at
+ xml.createdAt(format_datetime(created_at))
+ end
+ xml.rule do
+ xml.key(rule.key)
+ xml.name(rule.name)
+ end
+ xml.resource do
+ xml.key(snapshot.project.key)
+ xml.name(snapshot.project.name)
+ xml.scope(snapshot.project.scope)
+ xml.qualifier(snapshot.project.qualifier)
+ xml.language(snapshot.project.language)
+ end
+ end
+ end
+
+ def format_datetime(datetime)
+ datetime.strftime("%Y-%m-%dT%H:%M:%S%z")
+ end
+
+end
-<% form_for :review, @review do |f| %>\r
- <%= f.hidden_field :rule_failure_permanent_id -%>\r
- <%= f.hidden_field :review_type -%>\r
- \r
- <% if @review.review_type == "f-positive" %>\r
- <b>Reason for flagging this violation as a false-positive:</b>\r
- <% end %>\r
- <%= text_area :review_comment, :review_text, \r
- :id => "reviewText", :rows => 8, \r
- :style => "width:100%", :onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" -%>\r
- <br/>\r
- \r
- <div>\r
- <%\r
- if @review.review_type == "comments"\r
- button_text = "Post review"\r
- else\r
- button_text = "Switch-off violation"\r
- end\r
- %>\r
- <%= submit_to_remote "submit_btn", button_text, :url => { :action => 'create' }, :html => { :id => "submit_btn", :disabled => "true" } -%>\r
- \r
- <a onclick="$('reviewForm<%= @review.rule_failure_permanent_id.to_s -%>').style.display='none';" href="#">Cancel</a>\r
- <% if @review.review_type == "comments" %>\r
- \r
- <%= check_box_tag "assign_to_me", "me", true -%> Assign to me\r
- <% end %>\r
- </div>\r
- </div class="clear"></div> \r
+<% form_for :review, @review do |f| %>
+ <%= f.hidden_field :rule_failure_permanent_id -%>
+ <%= f.hidden_field :review_type -%>
+
+ <% if @review.review_type == "f-positive" %>
+ <b>Reason for flagging this violation as a false-positive:</b>
+ <% end %>
+ <%= text_area :review_comment, :review_text,
+ :id => "reviewText", :rows => 8,
+ :style => "width:100%", :onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" -%>
+ <br/>
+
+ <div>
+ <%
+ if @review.review_type == "comments"
+ button_text = "Post review"
+ else
+ button_text = "Switch-off violation"
+ end
+ %>
+ <%= submit_to_remote "submit_btn", button_text, :url => { :action => 'create' }, :html => { :id => "submit_btn", :disabled => "true" } -%>
+
+ <a onclick="$('reviewForm<%= @review.rule_failure_permanent_id.to_s -%>').style.display='none';" href="#">Cancel</a>
+ <% if @review.review_type == "comments" %>
+
+ <%= check_box_tag "assign_to_me", "me", true -%> Assign to me
+ <% end %>
+ </div>
+ </div class="clear"></div>
<% end %>
\ No newline at end of file
-<% form_for :review_comment, @review_comment do |f| %>\r
- <%= f.hidden_field :review_id %>\r
- <%= f.text_area :review_text, :rows => 8, \r
- :id => "commentText" + @rule_failure_permanent_id.to_s,\r
- :style => "width:100%",\r
- :onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" %>\r
- <br/>\r
- \r
- <% if @update_comment %>\r
- <%= submit_to_remote 'submit_btn', 'Update comment', \r
- :url => { :action => 'update_comment', \r
- :rule_failure_permanent_id => @rule_failure_permanent_id },\r
- :html => { :id => "submit_btn" } %>\r
- \r
- <%= link_to_remote 'Cancel', \r
- :url => { :action => 'display_violation', \r
- :rule_failure_permanent_id => @rule_failure_permanent_id },\r
- :update => "vId" + @rule_failure_permanent_id.to_s %> \r
- <% else %>\r
- <%= submit_to_remote 'submit_btn', 'Post comment', \r
- :url => { :action => 'create_comment', \r
- :rule_failure_permanent_id => @rule_failure_permanent_id },\r
- :html => { :id => "submit_btn", :disabled => true } %>\r
- \r
- <a onclick="$('reviewForm<%= @rule_failure_permanent_id.to_s -%>').style.display='none'; $('commentAction<%= @rule_failure_permanent_id.to_s -%>').style.display='';" href="#">Cancel</a>\r
- <% end %>\r
- \r
+<% form_for :review_comment, @review_comment do |f| %>
+ <%= f.hidden_field :review_id %>
+ <%= f.text_area :review_text, :rows => 8,
+ :id => "commentText" + @rule_failure_permanent_id.to_s,
+ :style => "width:100%",
+ :onKeyUp => "if (this.value=='') $('submit_btn').disabled='true'; else $('submit_btn').disabled='';" %>
+ <br/>
+
+ <% if @update_comment %>
+ <%= submit_to_remote 'submit_btn', 'Update comment',
+ :url => { :action => 'update_comment',
+ :rule_failure_permanent_id => @rule_failure_permanent_id },
+ :html => { :id => "submit_btn" } %>
+
+ <%= link_to_remote 'Cancel',
+ :url => { :action => 'display_violation',
+ :rule_failure_permanent_id => @rule_failure_permanent_id },
+ :update => "vId" + @rule_failure_permanent_id.to_s %>
+ <% else %>
+ <%= submit_to_remote 'submit_btn', 'Post comment',
+ :url => { :action => 'create_comment',
+ :rule_failure_permanent_id => @rule_failure_permanent_id },
+ :html => { :id => "submit_btn", :disabled => true } %>
+
+ <a onclick="$('reviewForm<%= @rule_failure_permanent_id.to_s -%>').style.display='none'; $('commentAction<%= @rule_failure_permanent_id.to_s -%>').style.display='';" href="#">Cancel</a>
+ <% end %>
+
<% end %>
\ No newline at end of file
- <div id="review<%= review.id -%>">\r
- <div>\r
- <b>Review #<%= review.id -%> - <%= h(review.title) -%></b>\r
- <br/>\r
- <% if review.assignee %>\r
- <i>Assigned to <%= h(review.assignee.name) -%></i>\r
- <% end %>\r
- </div>\r
- \r
- <div style="margin-top: 10px; margin-left: 20px">\r
- <% unless review.review_comments.blank?\r
- last_comment = review.review_comments.last\r
- review.review_comments.each do |review_comment|\r
- %>\r
- <table style="width:100%; margin-bottom: 3px">\r
- <tr style="border: solid 1px grey; background-color: #F7F7F7">\r
- <td style="width:180px; vertical-align:top; padding: 2px 2px 2px 10px; font-weight: bold">\r
- <%= image_tag("user.png") -%> <b><%= h(review_comment.user.name) -%></b>\r
- </td>\r
- <td style="vertical-align: top; padding: 2px 10px 2px 2px; color: grey; text-align: right; font-style: italic">\r
- <%= l review_comment.created_at -%>\r
- </td>\r
- </tr>\r
- <tr style="border: solid 1px grey;">\r
- <td colspan="2" style="padding: 5px;">\r
- <% if review_comment == last_comment %>\r
- <div id="lastComment<%= review.id -%>">\r
- <%= h(review_comment.review_text) -%>\r
- </div>\r
- <% else %>\r
- <%= h(review_comment.review_text) -%>\r
- <% end %>\r
- </td>\r
- </tr>\r
- </table>\r
- <% \r
- end\r
- end\r
- %>\r
- \r
- <% if current_user %>\r
- <div style="text-align: right; padding: 5px">\r
- <% if current_user.id == review.review_comments.last.user_id %>\r
- <%= image_tag("pencil.png") -%>\r
- <%= link_to_remote "Edit my last comment", \r
- :url => { :controller => "reviews", :action => "form_comment", \r
- :review_id => review.id, \r
- :rule_failure_permanent_id => review.rule_failure_permanent_id,\r
- :review_text => review.review_comments.last.review_text,\r
- :update_comment => "true" },\r
- :update => "lastComment" + review.id.to_s, \r
- :complete => "$('commentText" + review.id.to_s + "').focus()" -%>\r
- \r
- <% end %>\r
- <%= image_tag("pencil.png") -%>\r
- <%= link_to_remote "Add a new comment", \r
- :url => { :controller => "reviews", :action => "form_comment", :review_id => review.id, :rule_failure_permanent_id => review.rule_failure_permanent_id },\r
- :update => "createComment" + review.id.to_s, \r
- :complete => "$('commentText" + review.id.to_s + "').focus()" -%>\r
- </div>\r
- <div id="createComment<%= review.id -%>"></div>\r
- <% end %>\r
- </div>\r
-\r
- </div>\r
+ <div id="review<%= review.id -%>">
+ <div>
+ <b>Review #<%= review.id -%> - <%= h(review.title) -%></b>
+ <br/>
+ <% if review.assignee %>
+ <i>Assigned to <%= h(review.assignee.name) -%></i>
+ <% end %>
+ </div>
+
+ <div style="margin-top: 10px; margin-left: 20px">
+ <% unless review.review_comments.blank?
+ last_comment = review.review_comments.last
+ review.review_comments.each do |review_comment|
+ %>
+ <table style="width:100%; margin-bottom: 3px">
+ <tr style="border: solid 1px grey; background-color: #F7F7F7">
+ <td style="width:180px; vertical-align:top; padding: 2px 2px 2px 10px; font-weight: bold">
+ <%= image_tag("user.png") -%> <b><%= h(review_comment.user.name) -%></b>
+ </td>
+ <td style="vertical-align: top; padding: 2px 10px 2px 2px; color: grey; text-align: right; font-style: italic">
+ <%= l review_comment.created_at -%>
+ </td>
+ </tr>
+ <tr style="border: solid 1px grey;">
+ <td colspan="2" style="padding: 5px;">
+ <% if review_comment == last_comment %>
+ <div id="lastComment<%= review.id -%>">
+ <%= h(review_comment.review_text) -%>
+ </div>
+ <% else %>
+ <%= h(review_comment.review_text) -%>
+ <% end %>
+ </td>
+ </tr>
+ </table>
+ <%
+ end
+ end
+ %>
+
+ <% if current_user %>
+ <div style="text-align: right; padding: 5px">
+ <% if current_user.id == review.review_comments.last.user_id %>
+ <%= image_tag("pencil.png") -%>
+ <%= link_to_remote "Edit my last comment",
+ :url => { :controller => "reviews", :action => "form_comment",
+ :review_id => review.id,
+ :rule_failure_permanent_id => review.rule_failure_permanent_id,
+ :review_text => review.review_comments.last.review_text,
+ :update_comment => "true" },
+ :update => "lastComment" + review.id.to_s,
+ :complete => "$('commentText" + review.id.to_s + "').focus()" -%>
+
+ <% end %>
+ <%= image_tag("pencil.png") -%>
+ <%= link_to_remote "Add a new comment",
+ :url => { :controller => "reviews", :action => "form_comment", :review_id => review.id, :rule_failure_permanent_id => review.rule_failure_permanent_id },
+ :update => "createComment" + review.id.to_s,
+ :complete => "$('commentText" + review.id.to_s + "').focus()" -%>
+ </div>
+ <div id="createComment<%= review.id -%>"></div>
+ <% end %>
+ </div>
+
+ </div>
-if @violation\r
- page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation }\r
-else\r
- page.replace_html "reviewForm" + @rule_failure_permanent_id.to_s, :partial => "form_comment"\r
+if @violation
+ page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation }
+else
+ page.replace_html "reviewForm" + @rule_failure_permanent_id.to_s, :partial => "form_comment"
end
\ No newline at end of file
-if @violation\r
- page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation }\r
-else \r
- page.replace_html "reviewForm" + @review.rule_failure_permanent_id.to_s, :partial => "form"\r
+if @violation
+ page.replace "vId" + @violation.permanent_id.to_s, :partial => "resource/violation", :locals => { :violation => @violation }
+else
+ page.replace_html "reviewForm" + @review.rule_failure_permanent_id.to_s, :partial => "form"
end
\ No newline at end of file
-#\r
-# Sonar, entreprise quality control tool.\r
-# Copyright (C) 2008-2011 SonarSource\r
-# mailto:contact AT sonarsource DOT com\r
-#\r
-# Sonar is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 3 of the License, or (at your option) any later version.\r
-#\r
-# Sonar is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with Sonar; if not, write to the Free Software\r
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02\r
-#\r
-\r
-#\r
-# Sonar 2.8\r
-#\r
-class CreateReview < ActiveRecord::Migration\r
-\r
- def self.up\r
- create_table 'reviews' do |t|\r
- t.column 'created_at', :datetime\r
- t.column 'updated_at', :datetime\r
- t.column 'user_id', :integer, :null => true\r
- t.column 'assignee_id', :integer, :null => true\r
- t.column 'title', :string, :null => true, :limit => 500\r
- t.column 'review_type', :string, :null => true, :limit => 10\r
- t.column 'status', :string, :null => true, :limit => 10\r
- t.column 'severity', :string, :null => true, :limit => 10\r
- t.column 'rule_failure_permanent_id', :integer, :null => true \r
- t.column 'resource_id', :integer, :null => true \r
- t.column 'resource_line', :integer, :null => true \r
- end\r
- \r
- create_table 'review_comments' do |t|\r
- t.column 'created_at', :datetime\r
- t.column 'updated_at', :datetime\r
- t.column 'review_id', :integer\r
- t.column 'user_id', :integer, :null => true\r
- t.column 'review_text', :text, :null => true\r
- end\r
- \r
- alter_to_big_primary_key('reviews')\r
- alter_to_big_primary_key('review_comments')\r
- \r
- end\r
-\r
-end\r
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# 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
+#
+
+#
+# Sonar 2.8
+#
+class CreateReview < ActiveRecord::Migration
+
+ def self.up
+ create_table 'reviews' do |t|
+ t.column 'created_at', :datetime
+ t.column 'updated_at', :datetime
+ t.column 'user_id', :integer, :null => true
+ t.column 'assignee_id', :integer, :null => true
+ t.column 'title', :string, :null => true, :limit => 500
+ t.column 'review_type', :string, :null => true, :limit => 10
+ t.column 'status', :string, :null => true, :limit => 10
+ t.column 'severity', :string, :null => true, :limit => 10
+ t.column 'rule_failure_permanent_id', :integer, :null => true
+ t.column 'resource_id', :integer, :null => true
+ t.column 'resource_line', :integer, :null => true
+ end
+
+ create_table 'review_comments' do |t|
+ t.column 'created_at', :datetime
+ t.column 'updated_at', :datetime
+ t.column 'review_id', :integer
+ t.column 'user_id', :integer, :null => true
+ t.column 'review_text', :text, :null => true
+ end
+
+ alter_to_big_primary_key('reviews')
+ alter_to_big_primary_key('review_comments')
+
+ end
+
+end
#!/bin/sh
+
#
# NOTE: sonar must be built
#
unzip sonar-*.zip
cd sonar-*
bin/macosx-universal-64/sonar.sh console
-