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 ) {
    if ( LOG.isDebugEnabled() ) LOG.debug( "Highlightning source files for rule failures" );
    Map<File, List<RuleFailure>> failuresPerFile = orderFailuresPerFile(module.getRuleFailures());
    if ( LOG.isDebugEnabled() ) LOG.debug( "Rule failures ordered per file" );
    List<File> files = module.getFiles();
    for (File file : files) {
      List<RuleFailure> failuresForFile = failuresPerFile.get(file);
      if ( LOG.isDebugEnabled() ) LOG.debug( "Highlightning source file " + 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.