Package ch.hortis.sonar.core.service

Source Code of ch.hortis.sonar.core.service.SourcesHighlighterService

/*
* This program is copyright (c) 2007 Hortis-GRC SA.
*
* This file is part of Sonar.
* Sonar is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package ch.hortis.sonar.core.service;

import ch.hortis.sonar.model.File;
import ch.hortis.sonar.model.FileSource;
import ch.hortis.sonar.model.Parameter;
import ch.hortis.sonar.model.RuleFailure;
import ch.hortis.sonar.model.RuleFailureLevel;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SourcesHighlighterService implements Service {

  protected static final Logger LOG = LoggerFactory.getLogger(SourcesHighlighterService.class);

  private Pattern cssPattern = Pattern.compile("((?:\\.\\.\\/)*)stylesheet\\.css");
  private Pattern footerPattern = Pattern.compile("<hr/><div id=\"footer\">.+</div>");
  private Pattern hrefPattern = Pattern.compile("<a href=\"((?:\\.\\./)*((?:\\w+/)*)((\\w+\\.html)))\">");
  private Pattern sourceCodePattern = Pattern.compile("^<a name=\"(?:\\d+)\" href=\"#(?:\\d+)\">(\\d+)</a>\\s*");

  public void execute(Module module, List<Module> directSubmodules) {
    Map<File, List<RuleFailure>> failuresPerFile = orderFailuresPerFile(module.getRuleFailures());
    List<File> files = module.getFiles();
    for (File file : files) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Highlighting file " + file);
      }
      List<RuleFailure> failuresForFile = failuresPerFile.get(file);
      highlight(file, failuresForFile, files);
    }
  }

  private void highlight(File toHighlight, List<RuleFailure> failuresForFile, List<File> snapshotFiles) {
    FileSource source = toHighlight.getFileSource();
    if (source != null) {
      processCssAndFooter(source);
      highlightLines(toHighlight, failuresForFile, snapshotFiles);
    }
  }

  protected void processCssAndFooter(FileSource source) {
    String fileSource = source.getSource();
    fileSource = cssPattern.matcher(fileSource).replaceFirst("../../../stylesheets/highlighted-source.css");
    fileSource = footerPattern.matcher(fileSource).replaceFirst("");
    source.setSource(fileSource);
  }

  private void addTooltipActivators(FileSource source, Set<Integer> highlightedLines) {
    StringBuffer tootipJavaScript = new StringBuffer(4096);
    tootipJavaScript.append("<script src=\"../../../javascripts/prototype.js\" type=\"text/javascript\"></script>\n");
    tootipJavaScript.append("<script src=\"../../../javascripts/effects.js\" type=\"text/javascript\"></script>\n");
    tootipJavaScript.append("<script src=\"../../../javascripts/tooltip.js\" type=\"text/javascript\"></script>\n");
    tootipJavaScript.append("<script type=\"text/javascript\">\n");
    for (Integer lineNumber : highlightedLines) {
      tootipJavaScript.append("Tooltip.add('activator_")
          .append(lineNumber).append("', 'target_").append(lineNumber).append("');\n");
    }
    tootipJavaScript.append("</script>\n");

    source.setSource(source.getSource().replace("</body>", tootipJavaScript.toString() + "</body>"));
  }

  private void highlightLines(File toHighlight, List<RuleFailure> failuresForFile, List<File> snapshotFiles) {
    StringBuffer highlightedSource = new StringBuffer(32768);
    Set<Integer> highlightedLines = new HashSet<Integer>();
    FileSource fileSource = toHighlight.getFileSource();

    String[] lines = fileSource.getSource().split("\\n");
    for (String line1 : lines) {
      String line = line1.trim();
      if (line.length() == 0) {
        continue;
      }
      Matcher sourceLineMatcher = getSourceLineMatcher(line);
      if (sourceLineMatcher.find()) {
        int lineNumber = Integer.parseInt(sourceLineMatcher.group(1));
        int sourceCodeStart = sourceLineMatcher.end(0);
        List<RuleFailure> failuresForGivenLine = getFailuresForGivenLine(toHighlight, failuresForFile, lineNumber);
        if (failuresForGivenLine.size() > 0) {
          line = highlightLine(toHighlight, failuresForGivenLine, line, sourceCodeStart, lineNumber);
          highlightedLines.add(lineNumber);
        }
        line = replaceLineHrefs(snapshotFiles, line);
      }
      highlightedSource.append(line).append("\n");
    }
    fileSource.setSource(highlightedSource.toString());
    if (highlightedLines.size() > 0) {
      addTooltipActivators(fileSource, highlightedLines);
    }
  }

  protected Matcher getSourceLineMatcher(String line) {
    return sourceCodePattern.matcher(line);
  }

  protected String replaceLineHrefs(List<File> snapshotFiles, String line) {
    Matcher hrefMatcher = hrefPattern.matcher(line);
    while (hrefMatcher.find()) {
      String originalHref = hrefMatcher.group(1);
      String nameSpace = StringUtils.chop(hrefMatcher.group(2).replace('/', '.'));
      String fileName = hrefMatcher.group(3).replace(".html", ".java");

      File hrefFile = null;
      for (File file : snapshotFiles) {
        if (file.getFilename().equals(fileName) &&
            file.getNamespace().equals(nameSpace)) {
          hrefFile = file;
          break;
        }
      }
      if (hrefFile != null) {
        line = line.replace(originalHref, hrefFile.getId().toString());
      }
    }
    return line;
  }

  protected String highlightLine(File toHighlight, List<RuleFailure> failuresForGivenLine, String lineSource, int sourceCodeStart, int lineNumber) {

    StringBuffer tooltip = new StringBuffer(4096);
    tooltip.append("<span id=\"target_").append(lineNumber).append("\" class=\"tooltip\" style=\"visibility: hidden;\">");
    StringBuffer errorsMessages = new StringBuffer(512);
    StringBuffer warningsMessages = new StringBuffer(512);

    boolean hasErrors = false;
    boolean hasWarnings = false;

    for (RuleFailure failure : failuresForGivenLine) {
      Parameter column = failure.getParameter("column");
      String columnVal = "";
      if (column != null) {
        columnVal = "(col " + Integer.toString(column.getValue().intValue()) + ") ";
      }
      StringBuffer toAppend = null;
      if (failure.getLevel() == RuleFailureLevel.ERROR) {
        toAppend = errorsMessages;
        hasErrors = true;
      } else if (failure.getLevel() == RuleFailureLevel.WARNING) {
        toAppend = warningsMessages;
        hasWarnings = true;
      }
      if (toAppend != null) {
        toAppend.append("<p><span style=\"font-weight: bold;\">").append(failure.getRule().getRulesCategory().getName())
            .append(" - ").append(failure.getRule().getName()).append("</span> : ")
            .append(columnVal).append(failure.getMessage().trim()).append("</p>");
      }
    }
    if (errorsMessages.length() > 0) {
      if (warningsMessages.length() > 0) {
        tooltip.append("<div class=\"title\">Errors</div>");
      }
      tooltip.append("<div class=\"content\">").append(errorsMessages).append("</div>");
    }
    if (warningsMessages.length() > 0) {
      if (errorsMessages.length() > 0) {
        tooltip.append("<div class=\"title\">Warnings</div>");
      }
      tooltip.append("<div class=\"content\">").append(warningsMessages).append("</div>");
    }
    tooltip.append("</span>");

    String cssClass = "error";
    if (hasWarnings && !hasErrors) {
      cssClass = "warning";
    }

    StringBuffer highlightedLine = new StringBuffer(8192);
    highlightedLine.append(lineSource.substring(0, sourceCodeStart));
    highlightedLine.append("<span id=\"activator_").append(lineNumber).append("\"");
    highlightedLine.append(" class=\"").append(cssClass).append("\">");
    highlightedLine.append(lineSource.substring(sourceCodeStart));
    highlightedLine.append("</span>");
    highlightedLine.append(tooltip);

    lineSource = highlightedLine.toString();
    return lineSource;
  }

  private List<RuleFailure> getFailuresForGivenLine(File toHighlight, List<RuleFailure> failuresForFile, int lineNumber) {
    List<RuleFailure> failuresForGivenLine = new ArrayList<RuleFailure>();
    if (failuresForFile != null) {
      for (Iterator<RuleFailure> i = failuresForFile.iterator(); i.hasNext();) {
        RuleFailure failure = i.next();
        Parameter lineParam = failure.getParameter("line");
        if (lineParam.getValue().intValue() == lineNumber) {
          failuresForGivenLine.add(failure);
          i.remove();
        }
      }
    }
    return failuresForGivenLine;
  }

  private Map<File, List<RuleFailure>> orderFailuresPerFile(List<RuleFailure> failures) {
    Map<File, List<RuleFailure>> failuresPerFile = new HashMap<File, List<RuleFailure>>();
    for (RuleFailure failure : failures) {
      File failureFile = failure.getFile();
      List<RuleFailure> failuresForFile = failuresPerFile.get(failureFile);
      if (failuresForFile == null) {
        failuresForFile = new ArrayList<RuleFailure>();
        failuresPerFile.put(failureFile, failuresForFile);
      }
      failuresForFile.add(failure);
    }

    return failuresPerFile;
  }

}
TOP

Related Classes of ch.hortis.sonar.core.service.SourcesHighlighterService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.