001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube 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     * SonarQube 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     */
020    package org.sonar.batch.index;
021    
022    import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
023    import org.sonar.api.database.model.MeasureMapper;
024    import org.sonar.api.database.model.MeasureModel;
025    import org.sonar.api.database.model.Snapshot;
026    import org.sonar.api.measures.CoreMetrics;
027    import org.sonar.api.measures.Measure;
028    import org.sonar.api.measures.PersistenceMode;
029    import org.sonar.api.resources.Resource;
030    import org.sonar.api.rules.RuleFinder;
031    import org.sonar.batch.duplication.DuplicationCache;
032    import org.sonar.batch.duplication.DuplicationUtils;
033    import org.sonar.batch.index.Cache.Entry;
034    import org.sonar.core.persistence.DbSession;
035    import org.sonar.core.persistence.MyBatis;
036    
037    import java.util.List;
038    
039    public final class DuplicationPersister implements ScanPersister {
040      private final MyBatis mybatis;
041      private final RuleFinder ruleFinder;
042      private final SnapshotCache snapshotCache;
043      private final ResourceCache resourceCache;
044      private final DuplicationCache duplicationCache;
045      private final org.sonar.api.measures.MetricFinder metricFinder;
046    
047      public DuplicationPersister(MyBatis mybatis, RuleFinder ruleFinder,
048        SnapshotCache snapshotCache, ResourceCache resourceCache,
049        DuplicationCache duplicationCache, org.sonar.api.measures.MetricFinder metricFinder) {
050        this.mybatis = mybatis;
051        this.ruleFinder = ruleFinder;
052        this.snapshotCache = snapshotCache;
053        this.resourceCache = resourceCache;
054        this.duplicationCache = duplicationCache;
055        this.metricFinder = metricFinder;
056      }
057    
058      @Override
059      public void persist() {
060        // Don't use batch insert for duplications since keeping all data in memory can produce OOM
061        DbSession session = mybatis.openSession(false);
062        try {
063          MeasureMapper mapper = session.getMapper(MeasureMapper.class);
064          org.sonar.api.measures.Metric duplicationMetricWithId = metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY);
065          for (Entry<List<DuplicationGroup>> entry : duplicationCache.entries()) {
066            String effectiveKey = entry.key()[0].toString();
067            Measure measure = new Measure(duplicationMetricWithId, DuplicationUtils.toXml(entry.value())).setPersistenceMode(PersistenceMode.DATABASE);
068            Resource resource = resourceCache.get(effectiveKey);
069    
070            if (MeasurePersister.shouldPersistMeasure(resource, measure)) {
071              Snapshot snapshot = snapshotCache.get(effectiveKey);
072              MeasureModel measureModel = MeasurePersister.model(measure, ruleFinder).setSnapshotId(snapshot.getId());
073              mapper.insert(measureModel);
074            }
075          }
076    
077          session.commit();
078        } catch (Exception e) {
079          throw new IllegalStateException("Unable to save some measures", e);
080        } finally {
081          MyBatis.closeQuietly(session);
082        }
083      }
084    
085    }