org.sonar.server.db.migrations.v50.FileSourceDto.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.db.migrations.v50.FileSourceDto.java

Source

/*
 * SonarQube, open source software quality management tool.
 * Copyright (C) 2008-2014 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * SonarQube 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.
 *
 * SonarQube 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 this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.server.db.migrations.v50;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.text.CsvWriter;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.google.common.base.Charsets.UTF_8;

class FileSourceDto {

    private static final String SPACE_CHARS = "\t\n\r ";

    private Iterator<String> sourceSplitter;

    private final Map<Integer, String> revisions;
    private final Map<Integer, String> authors;
    private final Map<Integer, String> dates;
    private final Map<Integer, String> utHits;
    private final Map<Integer, String> utConditions;
    private final Map<Integer, String> utCoveredConditions;
    private final Map<Integer, String> itHits;
    private final Map<Integer, String> itConditions;
    private final Map<Integer, String> itCoveredConditions;
    private final Map<Integer, String> overallHits;
    private final Map<Integer, String> overallConditions;
    private final Map<Integer, String> overallCoveredConditions;
    private final List<List<Block>> duplicationGroups;

    FileSourceDto(String source, String revisions, String authors, String dates, String utHits, String utConditions,
            String utCoveredConditions, String itHits, String itConditions, String itCoveredConditions,
            String overallHits, String overallConditions, String overallCoveredConditions, String duplicationData) {
        sourceSplitter = Splitter.onPattern("\r?\n|\r").split(source).iterator();
        this.revisions = KeyValueFormat.parseIntString(revisions);
        this.authors = KeyValueFormat.parseIntString(authors);
        this.dates = KeyValueFormat.parseIntString(dates);
        this.utHits = KeyValueFormat.parseIntString(utHits);
        this.utConditions = KeyValueFormat.parseIntString(utConditions);
        this.utCoveredConditions = KeyValueFormat.parseIntString(utCoveredConditions);
        this.itHits = KeyValueFormat.parseIntString(itHits);
        this.itConditions = KeyValueFormat.parseIntString(itConditions);
        this.itCoveredConditions = KeyValueFormat.parseIntString(itCoveredConditions);
        this.overallHits = KeyValueFormat.parseIntString(overallHits);
        this.overallConditions = KeyValueFormat.parseIntString(overallConditions);
        this.overallCoveredConditions = KeyValueFormat.parseIntString(overallCoveredConditions);
        this.duplicationGroups = StringUtils.isNotBlank(duplicationData) ? parseDuplicationData(duplicationData)
                : Collections.<List<Block>>emptyList();
    }

    String[] getSourceData() {
        String highlighting = "";
        String symbolRefs = "";
        Map<Integer, String> duplicationsPerLine = computeDuplicationsPerLine(duplicationGroups);
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        int line = 0;
        String sourceLine = null;
        CsvWriter csv = CsvWriter.of(new OutputStreamWriter(output, UTF_8));
        StringBuilder lineHashes = new StringBuilder();
        while (sourceSplitter.hasNext()) {
            line++;
            sourceLine = sourceSplitter.next();
            lineHashes.append(lineChecksum(sourceLine)).append("\n");
            csv.values(revisions.get(line), authors.get(line), dates.get(line), utHits.get(line),
                    utConditions.get(line), utCoveredConditions.get(line), itHits.get(line), itConditions.get(line),
                    itCoveredConditions.get(line), overallHits.get(line), overallConditions.get(line),
                    overallCoveredConditions.get(line), highlighting, symbolRefs, duplicationsPerLine.get(line),
                    sourceLine);
        }
        csv.close();
        return new String[] { new String(output.toByteArray(), UTF_8), lineHashes.toString() };
    }

    public static String lineChecksum(String line) {
        String reducedLine = StringUtils.replaceChars(line, SPACE_CHARS, "");
        if (line.isEmpty()) {
            return "";
        }
        return DigestUtils.md5Hex(reducedLine);
    }

    private Map<Integer, String> computeDuplicationsPerLine(List<List<Block>> duplicationGroups) {
        Map<Integer, String> result = new HashMap<Integer, String>();
        if (duplicationGroups.isEmpty()) {
            return result;
        }
        Map<Integer, StringBuilder> dupPerLine = new HashMap<Integer, StringBuilder>();
        int blockId = 1;
        for (List<Block> group : duplicationGroups) {
            Block originBlock = group.get(0);
            addBlock(blockId, originBlock, dupPerLine);
            blockId++;
            for (int i = 1; i < group.size(); i++) {
                Block duplicate = group.get(i);
                if (duplicate.resourceKey.equals(originBlock.resourceKey)) {
                    addBlock(blockId, duplicate, dupPerLine);
                    blockId++;
                }
            }
        }
        for (Map.Entry<Integer, StringBuilder> entry : dupPerLine.entrySet()) {
            result.put(entry.getKey(), entry.getValue().toString());
        }
        return result;
    }

    private void addBlock(int blockId, Block block, Map<Integer, StringBuilder> dupPerLine) {
        int currentLine = block.start;
        for (int i = 0; i < block.length; i++) {
            if (dupPerLine.get(currentLine) == null) {
                dupPerLine.put(currentLine, new StringBuilder());
            }
            if (dupPerLine.get(currentLine).length() > 0) {
                dupPerLine.get(currentLine).append(',');
            }
            dupPerLine.get(currentLine).append(blockId);
            currentLine++;
        }

    }

    /**
     * Parses data of {@link CoreMetrics#DUPLICATIONS_DATA}.
     */
    private static List<List<Block>> parseDuplicationData(String data) {
        try {
            ImmutableList.Builder<List<Block>> groups = ImmutableList.builder();
            StringReader reader = new StringReader(data);
            SMInputFactory inputFactory = initStax();
            SMHierarchicCursor rootC = inputFactory.rootElementCursor(reader);
            // <duplications>
            rootC.advance();
            SMInputCursor groupsCursor = rootC.childElementCursor("g");
            while (groupsCursor.getNext() != null) {
                // <g>
                SMInputCursor blocksCursor = groupsCursor.childElementCursor("b");
                ImmutableList.Builder<Block> group = ImmutableList.builder();
                while (blocksCursor.getNext() != null) {
                    // <b>
                    String resourceKey = blocksCursor.getAttrValue("r");
                    int firstLine = getAttrIntValue(blocksCursor, "s");
                    int numberOfLines = getAttrIntValue(blocksCursor, "l");

                    group.add(new Block(resourceKey, firstLine, numberOfLines));
                }
                groups.add(group.build());
            }
            return groups.build();
        } catch (XMLStreamException e) {
            throw new SonarException(e.getMessage(), e);
        }
    }

    private static int getAttrIntValue(SMInputCursor cursor, String attrName) throws XMLStreamException {
        return cursor.getAttrIntValue(cursor.findAttrIndex(null, attrName));
    }

    private static SMInputFactory initStax() {
        XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
        return new SMInputFactory(xmlFactory);
    }

    private static class Block {

        final String resourceKey;
        final int start;
        final int length;

        public Block(String resourceKey, int s, int l) {
            this.resourceKey = resourceKey;
            this.start = s;
            this.length = l;
        }
    }

}