package org.activityinfo.server.command.handler;
/*
* #%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.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import org.activityinfo.legacy.shared.command.GetSyncRegions;
import org.activityinfo.legacy.shared.command.result.CommandResult;
import org.activityinfo.legacy.shared.command.result.SyncRegion;
import org.activityinfo.legacy.shared.command.result.SyncRegions;
import org.activityinfo.legacy.shared.exception.CommandException;
import org.activityinfo.legacy.shared.util.CollectionUtil;
import org.activityinfo.server.command.handler.sync.AdminUpdateBuilder;
import org.activityinfo.server.command.handler.sync.SiteTableUpdateBuilder;
import org.activityinfo.server.database.hibernate.entity.User;
import javax.persistence.EntityManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class GetSyncRegionsHandler implements CommandHandler<GetSyncRegions> {
private EntityManager entityManager;
@Inject
public GetSyncRegionsHandler(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override @SuppressWarnings("unchecked")
public CommandResult execute(GetSyncRegions cmd, User user) throws CommandException {
List<Object[]> databases = entityManager.createQuery("SELECT " +
"db.id, db.country.id, db.version, " +
"MAX(p.version) " +
"FROM UserDatabase db " +
"LEFT JOIN db.userPermissions p " +
"GROUP BY db.id").getResultList();
List<Integer> databaseIds = Lists.newArrayList();
Set<Integer> countryIds = Sets.newHashSet();
long schemaVersion = 1;
for (Object[] db : databases) {
databaseIds.add((Integer) db[0]);
countryIds.add((Integer) db[1]);
if (db[2] != null) {
schemaVersion = Math.max(schemaVersion, (Long) db[2]);
}
if (db[3] != null) {
schemaVersion = Math.max(schemaVersion, (Long) db[3]);
}
}
List<SyncRegion> regions = new ArrayList<SyncRegion>();
regions.add(new SyncRegion("schema", Long.toString(schemaVersion)));
regions.addAll(listAdminRegions(countryIds));
regions.addAll(listLocations(databaseIds));
regions.addAll(listSiteRegions(databaseIds));
return new SyncRegions(regions);
}
@SuppressWarnings("unchecked")
private Collection<? extends SyncRegion> listLocations(List<Integer> databases) {
List<SyncRegion> locationRegions = new ArrayList<SyncRegion>();
if (CollectionUtil.isNotEmpty(databases)) {
List<Object[]> regions = entityManager.createQuery("SELECT " +
"a.locationType.id, " +
"MAX(loc.timeEdited) " +
"FROM Activity a " +
"INNER JOIN a.locationType.locations loc " +
"WHERE a.database.id in (:dbs) " +
"GROUP BY a.locationType")
.setParameter("dbs", databases)
.getResultList();
for (Object[] region : regions) {
locationRegions.add(new SyncRegion("location/" + region[0], region[1].toString()));
}
}
return locationRegions;
}
@SuppressWarnings("unchecked")
private Collection<? extends SyncRegion> listAdminRegions(Set<Integer> countryIds) {
List<SyncRegion> adminRegions = new ArrayList<SyncRegion>();
if (CollectionUtil.isNotEmpty(countryIds)) {
List<Integer> levels = entityManager.createQuery("SELECT " +
"level.id " +
"FROM AdminLevel level " +
"WHERE level.country.id in (:countries) ")
.setParameter("countries", countryIds)
.getResultList();
for (Integer level : levels) {
adminRegions.add(new SyncRegion("admin/" + level,
Integer.toString(AdminUpdateBuilder.LAST_VERSION_NUMBER)));
}
}
return adminRegions;
}
/**
* We need a separate sync region for each Partner/UserDatabase combination
* because we may be given permission to view data at different times.
*/
@SuppressWarnings("unchecked")
private Collection<? extends SyncRegion> listSiteRegions(List<Integer> databases) {
List<SyncRegion> siteRegions = new ArrayList<SyncRegion>();
// our initial sync region manages the table schema
siteRegions.add(new SyncRegion("site-tables", SiteTableUpdateBuilder.CURRENT_VERSION));
if (CollectionUtil.isNotEmpty(databases)) {
// do one sync region per form
List<Object[]> regions = entityManager.createQuery("SELECT " +
"s.activity.id, " +
"MAX(s.timeEdited) " +
"FROM Site s " +
"WHERE s.activity.database.id in (:dbs) " +
"GROUP BY s.activity.id")
.setParameter("dbs", databases)
.getResultList();
for (Object[] region : regions) {
siteRegions.add(new SyncRegion("form-submissions/" + region[0], region[1].toString()));
}
}
return siteRegions;
}
}