001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program 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 * This program 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.fs.internal.charhandler; 021 022import java.io.File; 023import java.nio.ByteBuffer; 024import java.nio.CharBuffer; 025import java.nio.charset.CharacterCodingException; 026import java.nio.charset.CharsetEncoder; 027import java.nio.charset.CodingErrorAction; 028import java.nio.charset.StandardCharsets; 029import java.security.MessageDigest; 030 031import org.apache.commons.codec.digest.DigestUtils; 032import org.sonar.api.batch.fs.internal.FileMetadata.LineHashConsumer; 033 034public class LineHashComputer extends CharHandler { 035 private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest(); 036 private final CharsetEncoder encoder; 037 private final StringBuilder sb = new StringBuilder(); 038 private final LineHashConsumer consumer; 039 private final File file; 040 private int line = 1; 041 042 public LineHashComputer(LineHashConsumer consumer, File f) { 043 this.consumer = consumer; 044 this.file = f; 045 this.encoder = StandardCharsets.UTF_8.newEncoder() 046 .onMalformedInput(CodingErrorAction.REPLACE) 047 .onUnmappableCharacter(CodingErrorAction.REPLACE); 048 } 049 050 @Override 051 public void handleIgnoreEoL(char c) { 052 if (!Character.isWhitespace(c)) { 053 sb.append(c); 054 } 055 } 056 057 @Override 058 public void newLine() { 059 processBuffer(); 060 sb.setLength(0); 061 line++; 062 } 063 064 @Override 065 public void eof() { 066 if (this.line > 0) { 067 processBuffer(); 068 } 069 } 070 071 private void processBuffer() { 072 try { 073 if (sb.length() > 0) { 074 ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb)); 075 lineMd5Digest.update(encoded.array(), 0, encoded.limit()); 076 consumer.consume(line, lineMd5Digest.digest()); 077 } 078 } catch (CharacterCodingException e) { 079 throw new IllegalStateException("Error encoding line hash in file: " + file.getAbsolutePath(), e); 080 } 081 } 082}