package org.activityinfo.server.command.handler.sync;
/*
* #%L
* ActivityInfo Server
* %%
* Copyright (C) 2009 - 2013 UNICEF
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.bedatadriven.rebar.sql.client.query.SqlQuery;
import com.google.inject.Inject;
import org.activityinfo.legacy.shared.command.GetSyncRegionUpdates;
import org.activityinfo.legacy.shared.command.result.SyncRegionUpdate;
import org.activityinfo.legacy.shared.impl.Tables;
import org.activityinfo.server.database.hibernate.entity.User;
import javax.persistence.EntityManager;
import java.io.IOException;
public class SiteUpdateBuilder implements UpdateBuilder {
private final EntityManager entityManager;
private int activityId;
private SqliteBatchBuilder batch;
private long localVersion;
@Inject
public SiteUpdateBuilder(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public SyncRegionUpdate build(User user, GetSyncRegionUpdates request) throws IOException {
batch = new SqliteBatchBuilder();
activityId = parseActivityId(request.getRegionId());
localVersion = TimestampHelper.fromString(request.getLocalVersion());
SyncRegionUpdate update = new SyncRegionUpdate();
long latestVersion = queryLatestVersion();
if (latestVersion > localVersion) {
if(localVersion > 0) {
SqlQuery updatedQuery = updatedSites();
String updatedIds = SqlQueryUtil.queryIdSet(entityManager, updatedQuery);
deleteUpdated(updatedIds);
}
insertUpdatedSites();
insertUpdatedReportingPeriods();
insertUpdatedAttributeValues();
insertUpdatedIndicatorValues();
update.setSql(batch.build());
}
update.setComplete(true);
update.setVersion(Long.toString(latestVersion));
return update;
}
private int parseActivityId(String regionId) {
String[] parts = regionId.split("/");
return Integer.parseInt(parts[1]);
}
private void insertUpdatedIndicatorValues() {
SqlQuery ivQuery = updatedIndicatorValueQuery();
batch.insert().into(Tables.INDICATOR_VALUE).from(ivQuery).execute(entityManager);
}
private void insertUpdatedReportingPeriods() {
SqlQuery rpQuery = updatedPeriodQuery();
batch.insert().into(Tables.REPORTING_PERIOD).from(rpQuery).execute(entityManager);
}
private void insertUpdatedAttributeValues() {
SqlQuery avQuery = updatedAttributeValuesQuery();
batch.insert().into(Tables.ATTRIBUTE_VALUE).from(avQuery).execute(entityManager);
}
private void insertUpdatedSites() {
SqlQuery siteQuery = updatedSitesQuery();
// insert sites
batch.insert().into(Tables.SITE).from(siteQuery).execute(entityManager);
}
private void deleteUpdated(String updatedIds) throws IOException {
batch.addStatement("DELETE FROM attributevalue WHERE siteId IN " + updatedIds);
batch.addStatement("DELETE FROM indicatorvalue WHERE reportingperiodid IN " +
"(SELECT reportingperiodid FROM reportingperiod WHERE siteId IN " + updatedIds + ")");
batch.addStatement("DELETE FROM reportingperiod WHERE siteId IN " + updatedIds);
batch.addStatement("DELETE FROM site WHERE siteId IN " + updatedIds);
// there seem to be some clients left in an inconsistent state, probably
// due to errors on the server side earlier. So we clean up.
batch.addStatement("DELETE FROM indicatorvalue WHERE indicatorvalue.reportingperiodid NOT IN " +
"(select reportingperiodid from reportingperiod)");
}
private SqlQuery updatedSites() {
return SqlQuery.select()
.from(Tables.SITE, "s")
.leftJoin(Tables.ACTIVITY, "a")
.on("a.ActivityId=s.ActivityId")
.appendColumn("s.SiteId")
.where("a.ActivityId")
.equalTo(activityId)
.where("s.timeEdited")
.greaterThan(localVersion);
}
private SqlQuery updatedIndicatorValueQuery() {
return SqlQuery.select()
.from(Tables.INDICATOR_VALUE, "iv")
.leftJoin(Tables.REPORTING_PERIOD, "rp")
.on("rp.ReportingPeriodId=iv.ReportingPeriodId")
.leftJoin(Tables.SITE, "s")
.on("rp.SiteId = s.SiteId")
.leftJoin(Tables.ACTIVITY, "a")
.on("s.ActivityId = a.ActivityId")
.appendColumn("iv.IndicatorId")
.appendColumn("iv.ReportingPeriodId")
.appendColumn("iv.Value")
.appendColumn("iv.TextValue")
.appendColumn("iv.DateValue")
.appendColumn("iv.BooleanValue")
.where("a.ActivityId")
.equalTo(activityId)
.where("s.timeEdited")
.greaterThan(localVersion)
.whereTrue("s.dateDeleted IS NULL");
}
private SqlQuery updatedPeriodQuery() {
return SqlQuery.select()
.from(Tables.REPORTING_PERIOD, "rp")
.leftJoin(Tables.SITE, "s")
.on("rp.SiteId = s.SiteId")
.leftJoin(Tables.ACTIVITY, "a")
.on("s.ActivityId = a.ActivityId")
.appendColumn("rp.ReportingPeriodId")
.appendColumn("rp.SiteId")
.appendColumn("rp.Date1")
.appendColumn("rp.Date2")
.where("a.ActivityId")
.equalTo(activityId)
.where("s.timeEdited")
.greaterThan(localVersion)
.whereTrue("s.dateDeleted IS NULL");
}
private SqlQuery updatedAttributeValuesQuery() {
return SqlQuery.select()
.from(Tables.ATTRIBUTE_VALUE, "av")
.leftJoin(Tables.SITE, "s")
.on("av.SiteId = s.SiteId")
.leftJoin(Tables.ACTIVITY, "a")
.on("s.ActivityId = a.ActivityId")
.appendColumn("av.AttributeId")
.appendColumn("av.SiteId")
.appendColumn("av.Value")
.where("a.ActivityId")
.equalTo(activityId)
.where("s.timeEdited")
.greaterThan(localVersion)
.whereTrue("av.Value=1")
.whereTrue("s.dateDeleted IS NULL");
}
private SqlQuery updatedSitesQuery() {
return SqlQuery.select()
.from(Tables.SITE, "s")
.leftJoin(Tables.ACTIVITY, "a")
.on("a.ActivityId=s.ActivityId")
.appendColumn("s.SiteId")
.appendColumn("s.Date1")
.appendColumn("s.Date2")
.appendColumn("s.ActivityId")
.appendColumn("s.LocationId")
.appendColumn("s.PartnerId")
.appendColumn("s.ProjectId")
.appendColumn("s.Comments")
.appendColumn("s.timeEdited")
.where("s.timeEdited")
.greaterThan(localVersion)
.where("a.ActivityId")
.equalTo(activityId)
.whereTrue("s.dateDeleted IS NULL");
}
private long queryLatestVersion() {
SqlQuery query = SqlQuery.select()
.from(Tables.SITE, "s")
.leftJoin(Tables.ACTIVITY, "a")
.on("a.ActivityId=s.ActivityId")
.appendColumn("MAX(timeEdited)", "last")
.where("a.ActivityId")
.equalTo(activityId);
return SqlQueryUtil.queryLong(entityManager, query);
}
}