2 * Sonar, open source software quality management tool.
3 * Copyright (C) 2008-2012 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * Sonar is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * Sonar is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Sonar; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
20 package org.sonar.plugins.dbcleaner.runner;
22 import org.apache.commons.lang.builder.ToStringBuilder;
23 import org.hibernate.HibernateException;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.sonar.api.batch.PostJob;
27 import org.sonar.api.batch.SensorContext;
28 import org.sonar.api.database.DatabaseSession;
29 import org.sonar.api.database.model.Snapshot;
30 import org.sonar.api.resources.Project;
31 import org.sonar.api.utils.TimeProfiler;
32 import org.sonar.core.NotDryRun;
33 import org.sonar.plugins.dbcleaner.api.Purge;
34 import org.sonar.plugins.dbcleaner.api.PurgeContext;
36 import javax.persistence.Query;
39 public final class DeprecatedPurgePostJob implements PostJob {
41 private DatabaseSession session;
42 private Snapshot snapshot;
43 private Purge[] purges;
44 private Project project;
45 private static final Logger LOG = LoggerFactory.getLogger(DeprecatedPurgePostJob.class);
47 public DeprecatedPurgePostJob(DatabaseSession session, Project project, Snapshot snapshot, Purge[] purges) {
48 this.session = session;
49 this.project = project;
50 this.snapshot = snapshot;
51 this.purges = purges.clone();
54 public void executeOn(Project project, SensorContext context) {
55 if (shouldExecuteOn(project)) {
60 static boolean shouldExecuteOn(Project project) {
61 return project.isRoot();
65 TimeProfiler profiler = new TimeProfiler(LOG).start("Database optimization");
66 DefaultPurgeContext context = newContext();
67 LOG.debug("Snapshots to purge: " + context);
68 executePurges(context);
73 private void executePurges(DefaultPurgeContext context) {
74 TimeProfiler profiler = new TimeProfiler();
75 for (Purge purge : purges) {
77 profiler.start("Purge " + purge.getClass().getName());
79 session.commit(); // force hibernate to commit, so we're sure that the potential raised exception comes from this purge
81 } catch (javax.persistence.PersistenceException e) {
82 // Temporary workaround for MySQL deadlocks. The exception must not fail the build
83 // See https://jira.codehaus.org/browse/SONAR-2961 and https://jira.codehaus.org/browse/SONAR-2190
84 LOG.warn("Fail to execute purge: " + purge, e);
86 } catch (HibernateException e) {
87 // Temporary workaround for MySQL deadlocks. The exception must not fail the build
88 // See https://jira.codehaus.org/browse/SONAR-2961 and https://jira.codehaus.org/browse/SONAR-2190
89 LOG.warn("Fail to execute purge: " + purge, e);
94 private DefaultPurgeContext newContext() {
95 DefaultPurgeContext context = new DefaultPurgeContext(project, snapshot);
96 Snapshot previousLastSnapshot = getPreviousLastSnapshot();
97 if (previousLastSnapshot != null && previousLastSnapshot.getCreatedAt().before(snapshot.getCreatedAt())) {
98 context.setLastSnapshotId(previousLastSnapshot.getId());
103 private Snapshot getPreviousLastSnapshot() {
104 Query query = session.createQuery(
105 "SELECT s FROM " + Snapshot.class.getSimpleName() + " s " +
106 "WHERE s.status=:status AND s.resourceId=:resourceId AND s.createdAt<:date AND s.id <> :sid ORDER BY s.createdAt DESC");
107 query.setParameter("status", Snapshot.STATUS_PROCESSED);
108 query.setParameter("resourceId", snapshot.getResourceId());
109 query.setParameter("date", snapshot.getCreatedAt());
110 query.setParameter("sid", snapshot.getId());
111 query.setMaxResults(1);
112 return session.getSingleResult(query, null);
115 static final class DefaultPurgeContext implements PurgeContext {
117 private Project project;
118 private Integer currentSid;
119 private Integer previousSid;
121 public DefaultPurgeContext(Project project, Snapshot currentSnapshot) {
122 this(project, currentSnapshot, null);
125 public DefaultPurgeContext(Project project, Snapshot currentSnapshot, Snapshot previousSnapshot) {
126 this.project = project;
127 if (currentSnapshot != null) {
128 currentSid = currentSnapshot.getId();
130 if (previousSnapshot != null) {
131 previousSid = previousSnapshot.getId();
135 public DefaultPurgeContext setLastSnapshotId(Integer previousSid) {
136 this.previousSid = previousSid;
140 public Integer getSnapshotId() {
144 public Integer getPreviousSnapshotId() {
148 public Project getProject() {
153 public String toString() {
154 return new ToStringBuilder(this)
155 .append("currentSid", currentSid)
156 .append("previousSid", previousSid)