From ee7b180068da45ddbe70031a4d2cdd94c6c377d3 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 19 Apr 2011 19:36:14 +0400 Subject: [PATCH] Fix crlf --- COPYING | 2 +- deploy-docs.sh | 2 +- .../core/sensors/ReviewsDecorator.java | 142 +-- .../ViolationPersisterDecorator.java | 390 +++--- .../core/sensors/ReviewsDecoratorTest.java | 116 +- .../sensors/ReviewsDecoratorTest/fixture.xml | 104 +- quick-build.bat | 2 +- quick-build.sh | 2 +- .../sonar/batch/DefaultDecoratorContext.java | 350 +++--- .../org/sonar/batch/index/DefaultIndex.java | 1098 ++++++++--------- .../sonar/batch/index/ViolationPersister.java | 176 +-- .../sonar/batch/index/DefaultIndexTest.java | 476 +++---- .../batch/index/ViolationPersisterTest.java | 192 +-- .../index/ViolationPersisterTest/shared.xml | 48 +- ...opyPermanentIdFromPastViolation-result.xml | 52 +- ...opySwitchedOffFromPastViolation-result.xml | 54 +- .../shouldInsertViolations-result.xml | 50 +- .../sonar/jpa/session/JpaDatabaseSession.java | 526 ++++---- .../org/sonar/api/batch/DecoratorContext.java | 318 ++--- .../java/org/sonar/api/batch/SonarIndex.java | 364 +++--- .../sonar/api/database/DatabaseSession.java | 160 +-- .../java/org/sonar/api/rules/Violation.java | 506 ++++---- .../sonar/api/violations/ViolationQuery.java | 178 +-- .../app/controllers/resource_controller.rb | 674 +++++----- .../app/controllers/reviews_controller.rb | 526 ++++---- .../main/webapp/WEB-INF/app/models/review.rb | 144 +-- .../webapp/WEB-INF/app/models/rule_failure.rb | 168 +-- .../WEB-INF/app/views/reviews/_form.html.erb | 58 +- .../app/views/reviews/_form_comment.html.erb | 54 +- .../WEB-INF/app/views/reviews/_view.html.erb | 130 +- .../reviews/create_comment_result.js.rjs | 8 +- .../app/views/reviews/create_result.js.rjs | 8 +- .../WEB-INF/db/migrate/191_create_review.rb | 108 +- start-mac-derby.sh | 2 +- 34 files changed, 3594 insertions(+), 3594 deletions(-) diff --git a/COPYING b/COPYING index fc8a5de7edf..0e4fa8aaf20 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ - GNU LESSER GENERAL PUBLIC LICENSE + GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. diff --git a/deploy-docs.sh b/deploy-docs.sh index 6413b469e6a..6bcd4c42542 100644 --- a/deploy-docs.sh +++ b/deploy-docs.sh @@ -6,4 +6,4 @@ tar -cf docs.tar -C target/site/ . 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' diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsDecorator.java index 1faef7c4f66..c0b5b7ef94c 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsDecorator.java @@ -1,71 +1,71 @@ -/* - * 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(); - } - } - -} +/* + * 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(); + } + } + +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java index 455ec647f94..59ad0a168ca 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationPersisterDecorator.java @@ -1,196 +1,196 @@ -/* - * 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 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 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 pastViolations) { - Multimap 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 getChecksums(SnapshotSource source) { - return source == null || source.getData() == null ? Collections.emptyList() : getChecksums(source.getData()); - } - - static List getChecksums(String data) { - List result = Lists.newArrayList(); - StringInputStream stream = new StringInputStream(data); - try { - List 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 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 pastViolationsByRule) { - Collection 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 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 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(); - } - +/* + * 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 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 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 pastViolations) { + Multimap 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 getChecksums(SnapshotSource source) { + return source == null || source.getData() == null ? Collections.emptyList() : getChecksums(source.getData()); + } + + static List getChecksums(String data) { + List result = Lists.newArrayList(); + StringInputStream stream = new StringInputStream(data); + try { + List 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 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 pastViolationsByRule) { + Collection 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 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 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(); + } + } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsDecoratorTest.java index 1fd4da1748a..256cca68c04 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsDecoratorTest.java @@ -1,58 +1,58 @@ -/* - * 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"); - } -} +/* + * 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"); + } +} diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/ReviewsDecoratorTest/fixture.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/ReviewsDecoratorTest/fixture.xml index 24cf1cfb55d..ea16316886c 100644 --- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/ReviewsDecoratorTest/fixture.xml +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/ReviewsDecoratorTest/fixture.xml @@ -1,53 +1,53 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quick-build.bat b/quick-build.bat index a72fc8a4a6a..d83b5db5031 100644 --- a/quick-build.bat +++ b/quick-build.bat @@ -1,2 +1,2 @@ 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 diff --git a/quick-build.sh b/quick-build.sh index 75b97b0a504..f0755770766 100755 --- a/quick-build.sh +++ b/quick-build.sh @@ -9,4 +9,4 @@ echo '' 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 diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java index 4ca401c310a..3e5caae2957 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultDecoratorContext.java @@ -1,175 +1,175 @@ -/* - * 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 childrenContexts; - - public DefaultDecoratorContext(Resource resource, - SonarIndex index, - List 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 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 getMeasures(MeasuresFilter filter) { - return index.getMeasures(resource, filter); - } - - public Measure getMeasure(Metric metric) { - return index.getMeasure(resource, metric); - } - - public Collection getChildrenMeasures(MeasuresFilter filter) { - List 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 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 getViolations(ViolationQuery violationQuery) { - return index.getViolations(violationQuery); - } - - /** - * {@inheritDoc} - */ - public List getViolations() { - return index.getViolations(resource); - } - - public Dependency saveDependency(Dependency dependency) { - checkReadOnly("addDependency"); - return index.addDependency(dependency); - } - - public Set getDependencies() { - return index.getDependencies(); - } - - public Collection getIncomingDependencies() { - return index.getIncomingEdges(resource); - } - - public Collection getOutgoingDependencies() { - return index.getOutgoingEdges(resource); - } - - public List 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); - } -} +/* + * 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 childrenContexts; + + public DefaultDecoratorContext(Resource resource, + SonarIndex index, + List 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 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 getMeasures(MeasuresFilter filter) { + return index.getMeasures(resource, filter); + } + + public Measure getMeasure(Metric metric) { + return index.getMeasure(resource, metric); + } + + public Collection getChildrenMeasures(MeasuresFilter filter) { + List 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 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 getViolations(ViolationQuery violationQuery) { + return index.getViolations(violationQuery); + } + + /** + * {@inheritDoc} + */ + public List getViolations() { + return index.getViolations(resource); + } + + public Dependency saveDependency(Dependency dependency) { + checkReadOnly("addDependency"); + return index.addDependency(dependency); + } + + public Set getDependencies() { + return index.getDependencies(); + } + + public Collection getIncomingDependencies() { + return index.getIncomingEdges(resource); + } + + public Collection getOutgoingDependencies() { + return index.getOutgoingEdges(resource); + } + + public List 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); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java index b8f42c96040..5b4dd14c5fd 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -1,549 +1,549 @@ -/* - * 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 buckets = Maps.newHashMap(); - private Set dependencies = Sets.newHashSet(); - private Map> outgoingDependenciesByResource = Maps.newHashMap(); - private Map> 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> it = buckets.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - Resource resource = entry.getKey(); - if (!ResourceUtils.isSet(resource)) { - entry.getValue().clear(); - it.remove(); - } - } - - Set 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 getMeasures(Resource resource, MeasuresFilter 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 outgoingDeps = outgoingDependenciesByResource.get(dependency.getFrom()); - if (outgoingDeps == null) { - outgoingDeps = new HashMap(); - outgoingDependenciesByResource.put(dependency.getFrom(), outgoingDeps); - } - outgoingDeps.put(dependency.getTo(), dependency); - } - - private void registerIncomingDependency(Dependency dependency) { - Map incomingDeps = incomingDependenciesByResource.get(dependency.getTo()); - if (incomingDeps == null) { - incomingDeps = new HashMap(); - incomingDependenciesByResource.put(dependency.getTo(), incomingDeps); - } - incomingDeps.put(dependency.getFrom(), dependency); - } - - public Set getDependencies() { - return dependencies; - } - - public Dependency getEdge(Resource from, Resource to) { - Map 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 getVertices() { - return buckets.keySet(); - } - - public Collection getOutgoingEdges(Resource from) { - Map deps = outgoingDependenciesByResource.get(from); - if (deps != null) { - return deps.values(); - } - return Collections.emptyList(); - } - - public Collection getIncomingEdges(Resource to) { - Map deps = incomingDependenciesByResource.get(to); - if (deps != null) { - return deps.values(); - } - return Collections.emptyList(); - } - - Set getDependenciesBetweenProjects() { - Set 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 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 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 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 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 getChildren(Resource resource) { - return getChildren(resource, false); - } - - public List getChildren(Resource resource, boolean acceptExcluded) { - List 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; - } -} +/* + * 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 buckets = Maps.newHashMap(); + private Set dependencies = Sets.newHashSet(); + private Map> outgoingDependenciesByResource = Maps.newHashMap(); + private Map> 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> it = buckets.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + Resource resource = entry.getKey(); + if (!ResourceUtils.isSet(resource)) { + entry.getValue().clear(); + it.remove(); + } + } + + Set 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 getMeasures(Resource resource, MeasuresFilter 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 outgoingDeps = outgoingDependenciesByResource.get(dependency.getFrom()); + if (outgoingDeps == null) { + outgoingDeps = new HashMap(); + outgoingDependenciesByResource.put(dependency.getFrom(), outgoingDeps); + } + outgoingDeps.put(dependency.getTo(), dependency); + } + + private void registerIncomingDependency(Dependency dependency) { + Map incomingDeps = incomingDependenciesByResource.get(dependency.getTo()); + if (incomingDeps == null) { + incomingDeps = new HashMap(); + incomingDependenciesByResource.put(dependency.getTo(), incomingDeps); + } + incomingDeps.put(dependency.getFrom(), dependency); + } + + public Set getDependencies() { + return dependencies; + } + + public Dependency getEdge(Resource from, Resource to) { + Map 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 getVertices() { + return buckets.keySet(); + } + + public Collection getOutgoingEdges(Resource from) { + Map deps = outgoingDependenciesByResource.get(from); + if (deps != null) { + return deps.values(); + } + return Collections.emptyList(); + } + + public Collection getIncomingEdges(Resource to) { + Map deps = incomingDependenciesByResource.get(to); + if (deps != null) { + return deps.values(); + } + return Collections.emptyList(); + } + + Set getDependenciesBetweenProjects() { + Set 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 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 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 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 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 getChildren(Resource resource) { + return getChildren(resource, false); + } + + public List getChildren(Resource resource, boolean acceptExcluded) { + List 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; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java index cc156125a5d..2334c0f8714 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ViolationPersister.java @@ -1,88 +1,88 @@ -/* - * 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; - } - -} +/* + * 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; + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java index 6457cf2cc43..48946226df4 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java @@ -1,238 +1,238 @@ -/* - * 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()); - } - -} +/* + * 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()); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java index d1d3b775f5c..bb5bc1a34e9 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/ViolationPersisterTest.java @@ -1,96 +1,96 @@ -/* - * 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"); - } -} +/* + * 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"); + } +} diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shared.xml index cc50133e0bd..90a3f202297 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shared.xml +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shared.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopyPermanentIdFromPastViolation-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopyPermanentIdFromPastViolation-result.xml index 842a7e10765..881a88dc3bb 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopyPermanentIdFromPastViolation-result.xml +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopyPermanentIdFromPastViolation-result.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml index f72c573676d..bc366b16a45 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldCopySwitchedOffFromPastViolation-result.xml @@ -1,27 +1,27 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldInsertViolations-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldInsertViolations-result.xml index 765a84bae8c..3b3215ffe11 100644 --- a/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldInsertViolations-result.xml +++ b/sonar-batch/src/test/resources/org/sonar/batch/index/ViolationPersisterTest/shouldInsertViolations-result.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java b/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java index 6533b5ae5cf..ab3ee2417d0 100644 --- a/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java +++ b/sonar-core/src/main/java/org/sonar/jpa/session/JpaDatabaseSession.java @@ -1,263 +1,263 @@ -/* - * 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 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 reattach(Class 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 defaultValue, if not found - * @throws NonUniqueResultException if more than one result - */ - public 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 result = query.getResultList(); - - if (result.size() == 1) { - return result.get(0); - - } else if (result.isEmpty()) { - return defaultValue; - - } else { - Set uniqueResult = new HashSet(result); - if (uniqueResult.size() > 1) { - throw new NonUniqueResultException("Expected single result, but got : " + result.toString()); - } else { - return uniqueResult.iterator().next(); - } - } - } - - public T getEntity(Class entityClass, Object id) { - startTransaction(); - return getEntityManager().find(entityClass, id); - } - - /** - * @return the result or null, if not found - * @throws NonUniqueResultException if more than one result - */ - public T getSingleResult(Class 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 List getResults(Class entityClass, Object... criterias) { - return getQueryForCriterias(entityClass, true, criterias).getResultList(); - } - - public List getResults(Class 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 mappedCriterias = new HashMap(); - 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 entry : mappedCriterias.entrySet()) { - query.setParameter(entry.getKey(), entry.getValue()); - } - return query; - } - return getEntityManager().createQuery(hql.toString()); - } - - private void buildCriteriasHQL(StringBuilder hql, Map mappedCriterias) { - for (Iterator i = mappedCriterias.keySet().iterator(); i.hasNext();) { - String criteria = i.next(); - hql.append("o.").append(criteria).append("=:").append(criteria); - if (i.hasNext()) { - hql.append(" AND "); - } - } - } - -} +/* + * 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 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 reattach(Class 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 defaultValue, if not found + * @throws NonUniqueResultException if more than one result + */ + public 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 result = query.getResultList(); + + if (result.size() == 1) { + return result.get(0); + + } else if (result.isEmpty()) { + return defaultValue; + + } else { + Set uniqueResult = new HashSet(result); + if (uniqueResult.size() > 1) { + throw new NonUniqueResultException("Expected single result, but got : " + result.toString()); + } else { + return uniqueResult.iterator().next(); + } + } + } + + public T getEntity(Class entityClass, Object id) { + startTransaction(); + return getEntityManager().find(entityClass, id); + } + + /** + * @return the result or null, if not found + * @throws NonUniqueResultException if more than one result + */ + public T getSingleResult(Class 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 List getResults(Class entityClass, Object... criterias) { + return getQueryForCriterias(entityClass, true, criterias).getResultList(); + } + + public List getResults(Class 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 mappedCriterias = new HashMap(); + 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 entry : mappedCriterias.entrySet()) { + query.setParameter(entry.getKey(), entry.getValue()); + } + return query; + } + return getEntityManager().createQuery(hql.toString()); + } + + private void buildCriteriasHQL(StringBuilder hql, Map mappedCriterias) { + for (Iterator i = mappedCriterias.keySet().iterator(); i.hasNext();) { + String criteria = i.next(); + hql.append("o.").append(criteria).append("=:").append(criteria); + if (i.hasNext()) { + hql.append(" AND "); + } + } + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/DecoratorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/DecoratorContext.java index af59b924da7..57103c691d0 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/DecoratorContext.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/DecoratorContext.java @@ -1,159 +1,159 @@ -/* - * 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 getChildren(); - - // MEASURES - - /** - * Find a measure for the resource - */ - Measure getMeasure(Metric metric); - - /** - * Never return null. - */ - M getMeasures(MeasuresFilter filter); - - /** - * Never return null. - */ - Collection getChildrenMeasures(MeasuresFilter filter); - - /** - * @return the resource children measures for the given metric - */ - Collection 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 getDependencies(); - - Collection getIncomingDependencies(); - - Collection 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 getViolations(ViolationQuery violationQuery); - - /** - * Returns all the active (= non switched-off) violations found on the current resource. - * - * @return the list of violations - */ - List 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 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); - -} +/* + * 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 getChildren(); + + // MEASURES + + /** + * Find a measure for the resource + */ + Measure getMeasure(Metric metric); + + /** + * Never return null. + */ + M getMeasures(MeasuresFilter filter); + + /** + * Never return null. + */ + Collection getChildrenMeasures(MeasuresFilter filter); + + /** + * @return the resource children measures for the given metric + */ + Collection 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 getDependencies(); + + Collection getIncomingDependencies(); + + Collection 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 getViolations(ViolationQuery violationQuery); + + /** + * Returns all the active (= non switched-off) violations found on the current resource. + * + * @return the list of violations + */ + List 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 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); + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java index f2a09f9a6ce..89133b1c6b8 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java @@ -1,182 +1,182 @@ -/* - * 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 { - - /** - * 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 getResource(R reference); - - /** - * @since 2.6 - */ - public abstract Resource getParent(Resource reference); - - /** - * @since 2.6 - */ - - public abstract Collection 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 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 getMeasures(Resource resource, MeasuresFilter 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 getViolations(ViolationQuery violationQuery); - - /** - * Returns all the active (= non switched-off) violations found on the given resource. Equivalent to - * {@link #getViolations(ViolationQuery)} called with ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true) - * as a parameter. - * - * @since 2.7 - * @param the - * resource on which violations are searched - * @return the list of violations - */ - public final List 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 getDependencies(); - - public abstract void addLink(ProjectLink link); - - public abstract void deleteLink(String key); - - public abstract List 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 getOutgoingDependencies(Resource from) { - return getOutgoingEdges(from); - } - - public final Collection getIncomingDependencies(Resource to) { - return getIncomingEdges(to); - } -} +/* + * 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 { + + /** + * 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 getResource(R reference); + + /** + * @since 2.6 + */ + public abstract Resource getParent(Resource reference); + + /** + * @since 2.6 + */ + + public abstract Collection 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 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 getMeasures(Resource resource, MeasuresFilter 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 getViolations(ViolationQuery violationQuery); + + /** + * Returns all the active (= non switched-off) violations found on the given resource. Equivalent to + * {@link #getViolations(ViolationQuery)} called with ViolationQuery.create().forResource(resource).ignoreSwitchedOff(true) + * as a parameter. + * + * @since 2.7 + * @param the + * resource on which violations are searched + * @return the list of violations + */ + public final List 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 getDependencies(); + + public abstract void addLink(ProjectLink link); + + public abstract void deleteLink(String key); + + public abstract List 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 getOutgoingDependencies(Resource from) { + return getOutgoingEdges(from); + } + + public final Collection getIncomingDependencies(Resource to) { + return getIncomingEdges(to); + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/database/DatabaseSession.java b/sonar-plugin-api/src/main/java/org/sonar/api/database/DatabaseSession.java index dc416bc5257..19bf31cd5c6 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/database/DatabaseSession.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/database/DatabaseSession.java @@ -1,80 +1,80 @@ -/* - * 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 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 reattach(Class entityClass, Object primaryKey); - - public abstract Query createQuery(String hql); - - public abstract Query createNativeQuery(String sql); - - public abstract T getSingleResult(Query query, T defaultValue); - - public abstract T getEntity(Class entityClass, Object id); - - public abstract T getSingleResult(Class entityClass, Object... criterias); - - public abstract List getResults(Class entityClass, Object... criterias); - - public abstract List getResults(Class entityClass); -} +/* + * 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 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 reattach(Class entityClass, Object primaryKey); + + public abstract Query createQuery(String hql); + + public abstract Query createNativeQuery(String sql); + + public abstract T getSingleResult(Query query, T defaultValue); + + public abstract T getEntity(Class entityClass, Object id); + + public abstract T getSingleResult(Class entityClass, Object... criterias); + + public abstract List getResults(Class entityClass, Object... criterias); + + public abstract List getResults(Class entityClass); +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java index fd2b06ec1c2..3e4aa063a8b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Violation.java @@ -1,253 +1,253 @@ -/* - * 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); - } - -} +/* + * 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); + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java b/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java index e9f5ebdbdfa..10be756b640 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/violations/ViolationQuery.java @@ -1,89 +1,89 @@ -/* - * 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 create() - */ - 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; - } -} +/* + * 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 create() + */ + 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; + } +} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb index 12bfbb61ff6..bc4d569dd8d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb @@ -1,339 +1,339 @@ -# -# 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<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 '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< 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< '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<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? +# +# 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<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 '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< 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< '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<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 diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb index d5c3b7c56a0..ca8ef32259a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb @@ -1,263 +1,263 @@ -# -# 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 => "Cannot create the review : 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 => "Cannot create the comment : 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 => "Cannot modify the comment : 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 => "Cannot edit the review : 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 => "Cannot edit the review : 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 +# +# 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 => "Cannot create the review : 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 => "Cannot create the comment : 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 => "Cannot modify the comment : 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 => "Cannot edit the review : 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 => "Cannot edit the review : 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 diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb index df4179f309d..8cd7857e7ef 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb @@ -1,72 +1,72 @@ -# -# 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 +# +# 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 diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/rule_failure.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/rule_failure.rb index 45253ed2da9..bb62d4e80f2 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/rule_failure.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/rule_failure.rb @@ -1,84 +1,84 @@ -# -# 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 +# +# 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 diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form.html.erb index ceb5210de51..e9ac1210093 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form.html.erb @@ -1,30 +1,30 @@ -<% form_for :review, @review do |f| %> - <%= f.hidden_field :rule_failure_permanent_id -%> - <%= f.hidden_field :review_type -%> - - <% if @review.review_type == "f-positive" %> - Reason for flagging this violation as a false-positive: - <% 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='';" -%> -
- -
- <% - 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" } -%> -    - Cancel - <% if @review.review_type == "comments" %> -    - <%= check_box_tag "assign_to_me", "me", true -%> Assign to me - <% end %> -
- +<% form_for :review, @review do |f| %> + <%= f.hidden_field :rule_failure_permanent_id -%> + <%= f.hidden_field :review_type -%> + + <% if @review.review_type == "f-positive" %> + Reason for flagging this violation as a false-positive: + <% 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='';" -%> +
+ +
+ <% + 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" } -%> +    + Cancel + <% if @review.review_type == "comments" %> +    + <%= check_box_tag "assign_to_me", "me", true -%> Assign to me + <% end %> +
+ <% end %> \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form_comment.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form_comment.html.erb index 79ad5010402..016e8052e99 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form_comment.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_form_comment.html.erb @@ -1,28 +1,28 @@ -<% 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='';" %> -
- - <% 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 } %> -    - Cancel - <% end %> - +<% 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='';" %> +
+ + <% 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 } %> +    + Cancel + <% end %> + <% end %> \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_view.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_view.html.erb index 41de20ad0f7..aa12cbc38fb 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_view.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/_view.html.erb @@ -1,65 +1,65 @@ -
-
- Review #<%= review.id -%> - <%= h(review.title) -%> -
- <% if review.assignee %> - Assigned to <%= h(review.assignee.name) -%> - <% end %> -
- -
- <% unless review.review_comments.blank? - last_comment = review.review_comments.last - review.review_comments.each do |review_comment| - %> - - - - - - - - -
- <%= image_tag("user.png") -%> <%= h(review_comment.user.name) -%> - - <%= l review_comment.created_at -%> -
- <% if review_comment == last_comment %> -
- <%= h(review_comment.review_text) -%> -
- <% else %> - <%= h(review_comment.review_text) -%> - <% end %> -
- <% - end - end - %> - - <% if current_user %> -
- <% 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()" -%> -
-
- <% end %> -
- -
+
+
+ Review #<%= review.id -%> - <%= h(review.title) -%> +
+ <% if review.assignee %> + Assigned to <%= h(review.assignee.name) -%> + <% end %> +
+ +
+ <% unless review.review_comments.blank? + last_comment = review.review_comments.last + review.review_comments.each do |review_comment| + %> + + + + + + + + +
+ <%= image_tag("user.png") -%> <%= h(review_comment.user.name) -%> + + <%= l review_comment.created_at -%> +
+ <% if review_comment == last_comment %> +
+ <%= h(review_comment.review_text) -%> +
+ <% else %> + <%= h(review_comment.review_text) -%> + <% end %> +
+ <% + end + end + %> + + <% if current_user %> +
+ <% 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()" -%> +
+
+ <% end %> +
+ +
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_comment_result.js.rjs b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_comment_result.js.rjs index f177aae9cb2..3281ad51d3b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_comment_result.js.rjs +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_comment_result.js.rjs @@ -1,5 +1,5 @@ -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" +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 diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_result.js.rjs b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_result.js.rjs index 720e00f11b3..9e735242a22 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_result.js.rjs +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/reviews/create_result.js.rjs @@ -1,5 +1,5 @@ -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" +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 diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/191_create_review.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/191_create_review.rb index f67cadcf715..937c1f60ac9 100644 --- a/sonar-server/src/main/webapp/WEB-INF/db/migrate/191_create_review.rb +++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/191_create_review.rb @@ -1,54 +1,54 @@ -# -# 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 +# +# 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 diff --git a/start-mac-derby.sh b/start-mac-derby.sh index 5ed4ecb42ac..a26c7b10af0 100755 --- a/start-mac-derby.sh +++ b/start-mac-derby.sh @@ -1,4 +1,5 @@ #!/bin/sh + # # NOTE: sonar must be built # @@ -6,4 +7,3 @@ cd sonar-application/target/ unzip sonar-*.zip cd sonar-* bin/macosx-universal-64/sonar.sh console - -- 2.39.5