package org.activityinfo.server.event.sitehistory;
/*
* #%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.base.Strings;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.activityinfo.legacy.shared.command.Command;
import org.activityinfo.legacy.shared.command.GetSites;
import org.activityinfo.legacy.shared.command.SiteCommand;
import org.activityinfo.legacy.shared.command.result.SiteResult;
import org.activityinfo.legacy.shared.model.SiteDTO;
import org.activityinfo.legacy.shared.util.JsonUtil;
import org.activityinfo.server.command.DispatcherSync;
import org.activityinfo.server.database.hibernate.entity.Site;
import org.activityinfo.server.database.hibernate.entity.SiteHistory;
import org.activityinfo.server.database.hibernate.entity.User;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SiteHistoryProcessor {
private static final Logger LOGGER = Logger.getLogger(SiteHistoryProcessor.class.getName());
private static final String JSON_DELETE = "{\"_DELETE\":{\"type\":\"Boolean\",\"value\":true}}";
private final Provider<EntityManager> entityManager;
private final DispatcherSync dispatcher;
@Inject
public SiteHistoryProcessor(Provider<EntityManager> entityManager, DispatcherSync dispatcher) {
this.entityManager = entityManager;
this.dispatcher = dispatcher;
}
public void process(Command<?> cmd, final int userId, final int siteId) {
assert (cmd instanceof SiteCommand);
LOGGER.fine("persisting site history (site: " + siteId + ", user: " + userId + ")");
EntityManager em = entityManager.get();
// It's important to use getReference() here rather
// than find() becuase the site might not actually have
// been sent to the database at this point
Site site = em.getReference(Site.class, siteId);
User user = em.getReference(User.class, userId);
ChangeType type = ChangeType.getType(cmd);
if (!type.isNew()) {
Query q = em.createQuery("select count(*) from SiteHistory where site = :site");
q.setParameter("site", site);
Long count = (Long) q.getSingleResult();
if (count == 0) {
// update, but first entry -> repair history by adding baseline
// record with complete site json
LOGGER.fine("site is not new, but history was empty. Adding baseline record..");
SiteResult siteResult = dispatcher.execute(GetSites.byId(siteId));
SiteDTO siteDTO = siteResult.getData().get(0);
String fulljson = JsonUtil.encodeMap(siteDTO.getProperties()).toString();
SiteHistory baseline = new SiteHistory();
baseline.setSite(site);
baseline.setUser(user);
baseline.setJson(fulljson);
baseline.setTimeCreated(new Date().getTime());
baseline.setInitial(false);
persist(baseline);
}
}
String json = null;
if (type.isNewOrUpdate()) {
Map<String, Object> changeMap = ((SiteCommand) cmd).getProperties().getTransientMap();
if (!changeMap.isEmpty()) {
json = JsonUtil.encodeMap(changeMap).toString();
}
} else if (type.isDelete()) {
json = JSON_DELETE;
}
if (!Strings.isNullOrEmpty(json)) {
persistHistory(site, user, type, json);
}
}
public void persistHistory(Site site, User user, ChangeType type, Map<String, Object> changeMap) {
String json = "{}";
if (changeMap != null && !changeMap.isEmpty()) {
json = JsonUtil.encodeMap(changeMap).toString();
}
persistHistory(site, user, type, json);
}
public void persistHistory(Site site, User user, ChangeType type, String json) {
SiteHistory history = new SiteHistory();
history.setSite(site);
history.setUser(user);
history.setJson(json);
history.setTimeCreated(new Date().getTime());
history.setInitial(type.isNew());
persist(history);
}
private void persist(SiteHistory history) {
EntityManager em = entityManager.get();
EntityTransaction tx = em.getTransaction();
boolean manageManually = !tx.isActive();
try {
if (manageManually) {
tx.begin();
}
em.persist(history);
if (manageManually) {
tx.commit();
}
} catch (Exception e) {
try {
if (manageManually) {
tx.rollback();
}
} catch (Exception rollbackException) {
LOGGER.log(Level.SEVERE, "Exception rolling back failed transaction", rollbackException);
}
throw new RuntimeException(e);
}
}
}