001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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.batch;
021    
022    import org.slf4j.Logger;
023    import org.slf4j.LoggerFactory;
024    import org.sonar.api.batch.Purge;
025    import org.sonar.api.batch.PurgeContext;
026    import org.sonar.api.batch.SensorContext;
027    import org.sonar.api.database.DatabaseSession;
028    import org.sonar.api.database.model.Snapshot;
029    import org.sonar.api.resources.Project;
030    import org.sonar.api.utils.ServerHttpClient;
031    import org.sonar.api.utils.TimeProfiler;
032    
033    import javax.persistence.Query;
034    
035    public class FinalizeSnapshotsJob implements CoreJob {
036    
037      private DatabaseSession session;
038      private Purge[] purges;
039      private ServerHttpClient server;
040      private Snapshot snapshot;
041    
042      public FinalizeSnapshotsJob(ServerHttpClient server, DatabaseSession session, Purge[] purges, Snapshot snapshot) {
043        this.session = session;
044        this.purges = purges;
045        this.server = server;
046        this.snapshot = snapshot;
047      }
048    
049      public void execute(Project project, SensorContext context) {
050        if (shouldExecuteOn(project)) {
051          Snapshot previousLastSnapshot = getPreviousLastSnapshot(snapshot);
052          updateFlags(snapshot, previousLastSnapshot);
053          purge(snapshot, previousLastSnapshot);
054        }
055      }
056    
057      private boolean shouldExecuteOn(Project project) {
058        return project.isRoot();
059      }
060    
061      private Snapshot getPreviousLastSnapshot(Snapshot snapshot) {
062        Query query = session.createQuery(
063            "SELECT s FROM " + Snapshot.class.getSimpleName() + " s " +
064                "WHERE s.last=true AND s.resourceId=:resourceId");
065        query.setParameter("resourceId", snapshot.getResourceId());
066        return session.getSingleResult(query, null);
067      }
068    
069    
070      private void updateFlags(Snapshot rootSnapshot, Snapshot previousLastSnapshot) {
071        if (previousLastSnapshot != null && previousLastSnapshot.getCreatedAt().before(rootSnapshot.getCreatedAt())) {
072          setFlags(previousLastSnapshot, false, null);
073        }
074    
075        boolean isLast = (previousLastSnapshot == null || previousLastSnapshot.getCreatedAt().before(rootSnapshot.getCreatedAt()));
076        setFlags(rootSnapshot, isLast, Snapshot.STATUS_PROCESSED);
077        LoggerFactory.getLogger(getClass()).info("ANALYSIS SUCCESSFUL, you can browse {}", server.getUrl());
078      }
079    
080      private void setFlags(Snapshot snapshot, boolean last, String status) {
081        String hql = "UPDATE " + Snapshot.class.getSimpleName() + " SET last=:last";
082        if (status != null) {
083          hql += ", status=:status ";
084        }
085        hql += " WHERE root_snapshot_id=:rootId OR id=:rootId OR (path LIKE :path AND root_snapshot_id=:pathRootId)";
086    
087        Query query = session.createQuery(hql);
088        if (status != null) {
089          query.setParameter("status", status);
090          snapshot.setStatus(status);
091        }
092        query.setParameter("last", last);
093        query.setParameter("rootId", snapshot.getId());
094        query.setParameter("path", snapshot.getPath() + snapshot.getId() + ".%");
095        query.setParameter("pathRootId", (snapshot.getRootId() == null ? snapshot.getId() : snapshot.getRootId()));
096        query.executeUpdate();
097        session.commit();
098    
099        snapshot.setLast(last);
100      }
101    
102      private void purge(Snapshot currentSnapshot, Snapshot previousLastSnapshot) {
103        final Logger logger = LoggerFactory.getLogger(FinalizeSnapshotsJob.class);
104        TimeProfiler profiler = new TimeProfiler(logger).start("Database optimization");
105        PurgeContext context = createPurgeContext(currentSnapshot, previousLastSnapshot);
106        logger.debug("Snapshots to purge: " + context);
107        for (Purge purge : purges) {
108          logger.debug("Executing {}...", purge.getClass().getName());
109          purge.purge(context);
110        }
111        profiler.stop();
112      }
113    
114      private PurgeContext createPurgeContext(Snapshot currentSnapshot, Snapshot previousLastSnapshot) {
115        PurgeContext context = new PurgeContext(currentSnapshot);
116        if (previousLastSnapshot != null && previousLastSnapshot.getCreatedAt().before(currentSnapshot.getCreatedAt())) {
117          context.setLastSnapshotId(previousLastSnapshot.getId());
118        }
119        return context;
120      }
121    
122    }