org.sonar.core.purge.PurgeDao.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.core.purge.PurgeDao.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.core.purge;

import com.google.common.collect.Lists;
import org.apache.commons.lang.ArrayUtils;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @since 2.14
 */
public class PurgeDao {
    private static final Logger LOG = LoggerFactory.getLogger(PurgeDao.class);
    private final MyBatis mybatis;
    private final ResourceDao resourceDao;
    private final System2 system2;
    private final PurgeProfiler profiler;

    public PurgeDao(MyBatis mybatis, ResourceDao resourceDao, PurgeProfiler profiler, System2 system2) {
        this.mybatis = mybatis;
        this.resourceDao = resourceDao;
        this.profiler = profiler;
        this.system2 = system2;
    }

    public PurgeDao purge(PurgeConfiguration conf, PurgeListener purgeListener) {
        DbSession session = mybatis.openSession(true);
        try {
            purge(session, conf, purgeListener);
            session.commit();
        } finally {
            MyBatis.closeQuietly(session);
        }
        return this;
    }

    public void purge(DbSession session, PurgeConfiguration conf, PurgeListener purgeListener) {
        PurgeMapper mapper = session.getMapper(PurgeMapper.class);
        PurgeCommands commands = new PurgeCommands(session, mapper, profiler);
        List<ResourceDto> projects = getProjects(conf.rootProjectId(), session);
        for (ResourceDto project : projects) {
            LOG.info("-> Clean " + project.getLongName() + " [id=" + project.getId() + "]");
            deleteAbortedBuilds(project, commands);
            purge(project, conf.scopesWithoutHistoricalData(), commands);
        }
        for (ResourceDto project : projects) {
            disableOrphanResources(project, session, mapper, purgeListener);
        }
        deleteOldClosedIssues(conf, mapper);
    }

    private void deleteOldClosedIssues(PurgeConfiguration conf, PurgeMapper mapper) {
        Date toDate = conf.maxLiveDateOfClosedIssues();
        mapper.deleteOldClosedIssueChanges(conf.rootProjectId(), toDate);
        mapper.deleteOldClosedIssues(conf.rootProjectId(), toDate);
    }

    private void deleteAbortedBuilds(ResourceDto project, PurgeCommands commands) {
        if (hasAbortedBuilds(project.getId(), commands)) {
            LOG.info("<- Delete aborted builds");
            PurgeSnapshotQuery query = PurgeSnapshotQuery.create().setIslast(false).setStatus(new String[] { "U" })
                    .setRootProjectId(project.getId());
            commands.deleteSnapshots(query);
        }
    }

    private boolean hasAbortedBuilds(Long projectId, PurgeCommands commands) {
        PurgeSnapshotQuery query = PurgeSnapshotQuery.create().setIslast(false).setStatus(new String[] { "U" })
                .setResourceId(projectId);
        return !commands.selectSnapshotIds(query).isEmpty();
    }

    private void purge(ResourceDto project, String[] scopesWithoutHistoricalData, PurgeCommands purgeCommands) {
        List<Long> projectSnapshotIds = purgeCommands.selectSnapshotIds(
                PurgeSnapshotQuery.create().setResourceId(project.getId()).setIslast(false).setNotPurged(true));
        for (final Long projectSnapshotId : projectSnapshotIds) {
            LOG.info("<- Clean snapshot " + projectSnapshotId);
            if (!ArrayUtils.isEmpty(scopesWithoutHistoricalData)) {
                PurgeSnapshotQuery query = PurgeSnapshotQuery.create().setIslast(false)
                        .setScopes(scopesWithoutHistoricalData).setRootSnapshotId(projectSnapshotId);
                purgeCommands.deleteSnapshots(query);
            }

            PurgeSnapshotQuery query = PurgeSnapshotQuery.create().setRootSnapshotId(projectSnapshotId)
                    .setNotPurged(true);
            purgeCommands.purgeSnapshots(query);

            // must be executed at the end for reentrance
            purgeCommands.purgeSnapshots(PurgeSnapshotQuery.create().setId(projectSnapshotId).setNotPurged(true));
        }
    }

    private void disableOrphanResources(final ResourceDto project, final SqlSession session,
            final PurgeMapper purgeMapper, final PurgeListener purgeListener) {
        session.select("org.sonar.core.purge.PurgeMapper.selectResourceIdsToDisable", project.getId(),
                new ResultHandler() {
                    @Override
                    public void handleResult(ResultContext resultContext) {
                        IdUuidPair resourceIdUuid = (IdUuidPair) resultContext.getResultObject();
                        if (resourceIdUuid.getId() != null) {
                            disableResource(resourceIdUuid, purgeMapper);
                            purgeListener.onComponentDisabling(resourceIdUuid.getUuid());
                        }
                    }
                });
        session.commit();
    }

    public List<PurgeableSnapshotDto> selectPurgeableSnapshots(long resourceId) {
        DbSession session = mybatis.openSession(true);
        try {
            return selectPurgeableSnapshots(resourceId, session);
        } finally {
            MyBatis.closeQuietly(session);
        }
    }

    public List<PurgeableSnapshotDto> selectPurgeableSnapshots(long resourceId, DbSession session) {
        PurgeMapper mapper = session.getMapper(PurgeMapper.class);
        List<PurgeableSnapshotDto> result = Lists.newArrayList();
        result.addAll(mapper.selectPurgeableSnapshotsWithEvents(resourceId));
        result.addAll(mapper.selectPurgeableSnapshotsWithoutEvents(resourceId));
        // sort by date
        Collections.sort(result);
        return result;
    }

    public PurgeDao deleteResourceTree(IdUuidPair rootIdUuid) {
        final DbSession session = mybatis.openSession(true);
        final PurgeMapper mapper = session.getMapper(PurgeMapper.class);
        try {
            deleteProject(rootIdUuid.getId(), mapper, new PurgeCommands(session, profiler));
            deleteFileSources(rootIdUuid.getUuid(), new PurgeCommands(session, profiler));
            return this;
        } finally {
            MyBatis.closeQuietly(session);
        }
    }

    private void deleteFileSources(String rootUuid, PurgeCommands commands) {
        commands.deleteFileSources(rootUuid);
    }

    private void deleteProject(long rootProjectId, PurgeMapper mapper, PurgeCommands commands) {
        List<Long> childrenIds = mapper.selectProjectIdsByRootId(rootProjectId);
        for (Long childId : childrenIds) {
            deleteProject(childId, mapper, commands);
        }

        List<Long> resourceIds = mapper.selectResourceIdsByRootId(rootProjectId);
        commands.deleteResources(resourceIds);
    }

    private void disableResource(IdUuidPair resourceIdUuid, PurgeMapper mapper) {
        long resourceId = resourceIdUuid.getId();
        mapper.deleteResourceIndex(Arrays.asList(resourceId));
        mapper.setSnapshotIsLastToFalse(resourceId);
        mapper.deleteFileSourcesByUuid(resourceIdUuid.getUuid());
        mapper.disableResource(resourceId);
        mapper.resolveResourceIssuesNotAlreadyResolved(resourceId, new Date(system2.now()), system2.now());
    }

    public PurgeDao deleteSnapshots(PurgeSnapshotQuery query) {
        final DbSession session = mybatis.openSession(true);
        try {
            return deleteSnapshots(query, session);

        } finally {
            MyBatis.closeQuietly(session);
        }
    }

    public PurgeDao deleteSnapshots(PurgeSnapshotQuery query, final DbSession session) {
        new PurgeCommands(session, profiler).deleteSnapshots(query);
        return this;
    }

    /**
     * Load the whole tree of projects, including the project given in parameter.
     */
    private List<ResourceDto> getProjects(long rootProjectId, SqlSession session) {
        List<ResourceDto> projects = Lists.newArrayList();
        projects.add(resourceDao.getResource(rootProjectId, session));
        projects.addAll(resourceDao.getDescendantProjects(rootProjectId, session));
        return projects;
    }

    public List<String> selectPurgeableFiles(DbSession dbSession, Long projectId) {
        PurgeMapper mapper = dbSession.getMapper(PurgeMapper.class);
        return mapper.selectPurgeableFileUuids(projectId);
    }
}