001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.batch.sensor.highlighting.internal; 021 022import com.google.common.base.Preconditions; 023import com.google.common.collect.Sets; 024import org.sonar.api.batch.fs.InputFile; 025import org.sonar.api.batch.fs.internal.DefaultInputFile; 026import org.sonar.api.batch.sensor.highlighting.NewHighlighting; 027import org.sonar.api.batch.sensor.highlighting.TypeOfText; 028import org.sonar.api.batch.sensor.internal.DefaultStorable; 029import org.sonar.api.batch.sensor.internal.SensorStorage; 030 031import javax.annotation.Nullable; 032 033import java.util.Comparator; 034import java.util.Iterator; 035import java.util.Set; 036 037public class DefaultHighlighting extends DefaultStorable implements NewHighlighting { 038 039 private InputFile inputFile; 040 private Set<SyntaxHighlightingRule> syntaxHighlightingRuleSet; 041 042 public DefaultHighlighting() { 043 this(null); 044 } 045 046 public DefaultHighlighting(@Nullable SensorStorage storage) { 047 super(storage); 048 syntaxHighlightingRuleSet = Sets.newTreeSet(new Comparator<SyntaxHighlightingRule>() { 049 @Override 050 public int compare(SyntaxHighlightingRule left, SyntaxHighlightingRule right) { 051 int result = left.getStartPosition() - right.getStartPosition(); 052 if (result == 0) { 053 result = right.getEndPosition() - left.getEndPosition(); 054 } 055 return result; 056 } 057 }); 058 } 059 060 public Set<SyntaxHighlightingRule> getSyntaxHighlightingRuleSet() { 061 return syntaxHighlightingRuleSet; 062 } 063 064 private void checkOverlappingBoudaries() { 065 if (syntaxHighlightingRuleSet.size() > 1) { 066 Iterator<SyntaxHighlightingRule> it = syntaxHighlightingRuleSet.iterator(); 067 SyntaxHighlightingRule previous = it.next(); 068 while (it.hasNext()) { 069 SyntaxHighlightingRule current = it.next(); 070 if (previous.getEndPosition() > current.getStartPosition() && !(previous.getEndPosition() >= current.getEndPosition())) { 071 String errorMsg = String.format("Cannot register highlighting rule for characters from %s to %s as it " + 072 "overlaps at least one existing rule", current.getStartPosition(), current.getEndPosition()); 073 throw new IllegalStateException(errorMsg); 074 } 075 previous = current; 076 } 077 } 078 } 079 080 @Override 081 public DefaultHighlighting onFile(InputFile inputFile) { 082 Preconditions.checkNotNull(inputFile, "file can't be null"); 083 this.inputFile = inputFile; 084 return this; 085 } 086 087 public InputFile inputFile() { 088 return inputFile; 089 } 090 091 @Override 092 public DefaultHighlighting highlight(int startOffset, int endOffset, TypeOfText typeOfText) { 093 Preconditions.checkState(inputFile != null, "Call onFile() first"); 094 int maxValidOffset = ((DefaultInputFile) inputFile).lastValidOffset(); 095 checkOffset(startOffset, maxValidOffset, "startOffset"); 096 checkOffset(endOffset, maxValidOffset, "endOffset"); 097 Preconditions.checkArgument(startOffset < endOffset, "startOffset (" + startOffset + ") should be < endOffset (" + endOffset + ") for file " + inputFile + "."); 098 SyntaxHighlightingRule syntaxHighlightingRule = SyntaxHighlightingRule.create(startOffset, endOffset, 099 typeOfText); 100 this.syntaxHighlightingRuleSet.add(syntaxHighlightingRule); 101 return this; 102 } 103 104 private void checkOffset(int offset, int maxValidOffset, String label) { 105 Preconditions.checkArgument(offset >= 0 && offset <= maxValidOffset, "Invalid " + label + " " + offset + ". Should be >= 0 and <= " + maxValidOffset 106 + " for file " + inputFile); 107 } 108 109 @Override 110 protected void doSave() { 111 Preconditions.checkState(inputFile != null, "Call onFile() first"); 112 checkOverlappingBoudaries(); 113 storage.store(this); 114 } 115}