001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar 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 * Sonar 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
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.plugins.cpd.index;
021
022 import com.google.common.collect.Lists;
023 import com.google.common.collect.Maps;
024 import org.sonar.api.database.model.Snapshot;
025 import org.sonar.api.resources.Project;
026 import org.sonar.api.resources.Resource;
027 import org.sonar.batch.index.ResourcePersister;
028 import org.sonar.core.duplication.DuplicationDao;
029 import org.sonar.core.duplication.DuplicationUnitDto;
030 import org.sonar.duplications.block.Block;
031 import org.sonar.duplications.block.ByteArray;
032
033 import java.util.Collection;
034 import java.util.Collections;
035 import java.util.List;
036 import java.util.Map;
037
038 public class DbDuplicationsIndex {
039
040 private final Map<ByteArray, Collection<Block>> cache = Maps.newHashMap();
041
042 private final ResourcePersister resourcePersister;
043 private final int currentProjectSnapshotId;
044 private final Integer lastSnapshotId;
045 private final String languageKey;
046
047 private DuplicationDao dao;
048
049 public DbDuplicationsIndex(ResourcePersister resourcePersister, Project currentProject, DuplicationDao dao) {
050 this.dao = dao;
051 this.resourcePersister = resourcePersister;
052 Snapshot currentSnapshot = resourcePersister.getSnapshotOrFail(currentProject);
053 Snapshot lastSnapshot = resourcePersister.getLastSnapshot(currentSnapshot, false);
054 this.currentProjectSnapshotId = currentSnapshot.getId();
055 this.lastSnapshotId = lastSnapshot == null ? null : lastSnapshot.getId();
056 this.languageKey = currentProject.getLanguageKey();
057 }
058
059 int getSnapshotIdFor(Resource resource) {
060 return resourcePersister.getSnapshotOrFail(resource).getId();
061 }
062
063 public void prepareCache(Resource resource) {
064 int resourceSnapshotId = getSnapshotIdFor(resource);
065 List<DuplicationUnitDto> units = dao.selectCandidates(resourceSnapshotId, lastSnapshotId, languageKey);
066 cache.clear();
067 // TODO Godin: maybe remove conversion of units to blocks?
068 for (DuplicationUnitDto unit : units) {
069 String hash = unit.getHash();
070 String resourceKey = unit.getResourceKey();
071 int indexInFile = unit.getIndexInFile();
072 int startLine = unit.getStartLine();
073 int endLine = unit.getEndLine();
074
075 // TODO Godin: in fact we could work directly with id instead of key - this will allow to decrease memory consumption
076 Block block = Block.builder()
077 .setResourceId(resourceKey)
078 .setBlockHash(new ByteArray(hash))
079 .setIndexInFile(indexInFile)
080 .setLines(startLine, endLine)
081 .build();
082
083 // Group blocks by hash
084 Collection<Block> sameHash = cache.get(block.getBlockHash());
085 if (sameHash == null) {
086 sameHash = Lists.newArrayList();
087 cache.put(block.getBlockHash(), sameHash);
088 }
089 sameHash.add(block);
090 }
091 }
092
093 public Collection<Block> getByHash(ByteArray hash) {
094 Collection<Block> result = cache.get(hash);
095 if (result != null) {
096 return result;
097 } else {
098 return Collections.emptyList();
099 }
100 }
101
102 public void insert(Resource resource, Collection<Block> blocks) {
103 int resourceSnapshotId = getSnapshotIdFor(resource);
104
105 // TODO Godin: maybe remove conversion of blocks to units?
106 List<DuplicationUnitDto> units = Lists.newArrayList();
107 for (Block block : blocks) {
108 DuplicationUnitDto unit = new DuplicationUnitDto(
109 currentProjectSnapshotId,
110 resourceSnapshotId,
111 block.getBlockHash().toString(),
112 block.getIndexInFile(),
113 block.getStartLine(),
114 block.getEndLine());
115 units.add(unit);
116 }
117
118 dao.insert(units);
119 }
120
121 }