package gov.nasa.jpl.mbee.mdk.mms.sync.coordinated;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nomagic.magicdraw.core.Application;
import com.nomagic.magicdraw.core.Project;
import com.nomagic.magicdraw.core.project.ProjectEventListenerAdapter;
import com.nomagic.ui.ProgressStatusRunner;
import com.nomagic.uml2.ext.jmi.helpers.StereotypesHelper;
import gov.nasa.jpl.mbee.mdk.api.incubating.convert.Converters;
import gov.nasa.jpl.mbee.mdk.mms.jms.JMSUtils;
import gov.nasa.jpl.mbee.mdk.mms.sync.delta.DeltaSyncRunner;
import gov.nasa.jpl.mbee.mdk.mms.sync.delta.SyncElements;
import gov.nasa.jpl.mbee.mdk.mms.sync.jms.JMSMessageListener;
import gov.nasa.jpl.mbee.mdk.mms.sync.jms.JMSSyncProjectEventListenerAdapter;
import gov.nasa.jpl.mbee.mdk.json.JacksonUtils;
import gov.nasa.jpl.mbee.mdk.util.MDUtils;
import gov.nasa.jpl.mbee.mdk.util.TicketUtils;
import gov.nasa.jpl.mbee.mdk.options.MDKOptionsGroup;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by igomes on 6/22/16.
*/
public class CoordinatedSyncProjectEventListenerAdapter extends ProjectEventListenerAdapter {
private static final Map<Project, CoordinatedSyncProjectMapping> projectMappings = new ConcurrentHashMap<>();
private DeltaSyncRunner deltaSyncRunner;
@Override
public void projectClosed(Project project) {
CoordinatedSyncProjectMapping coordinatedSyncProjectMapping = getProjectMapping(project);
if (coordinatedSyncProjectMapping.isDisabled()) {
return;
}
projectMappings.remove(project);
}
@Override
public void projectReplaced(Project oldProject, Project newProject) {
projectClosed(oldProject);
projectOpened(newProject);
}
@Override
public void projectPreSaved(Project project, boolean savedInServer) {
deltaSyncRunner = null;
/*boolean tempDisabled = true;
if (tempDisabled) {
return;
}*/
if ( (project.isRemote() && !savedInServer)
|| !StereotypesHelper.hasStereotype(project.getModel(), "ModelManagementSystem")
|| CoordinatedSyncProjectEventListenerAdapter.getProjectMapping(project).isDisabled()
|| JMSSyncProjectEventListenerAdapter.getProjectMapping(project).getJmsMessageListener().isDisabled() ) {
// skip csync
return;
}
deltaSyncRunner = new DeltaSyncRunner(true, true, true);
ProgressStatusRunner.runWithProgressStatus(deltaSyncRunner, "Coordinated Sync", true, 0);
}
@Override
@SuppressWarnings("unchecked")
public void projectSaved(Project project, boolean savedInServer) {
CoordinatedSyncProjectMapping coordinatedSyncProjectMapping = getProjectMapping(project);
if (coordinatedSyncProjectMapping.isDisabled() || deltaSyncRunner == null || deltaSyncRunner.isFailure()) {
// CSync isn't running, so return
return;
}
JMSSyncProjectEventListenerAdapter.JMSSyncProjectMapping jmsSyncProjectMapping = JMSSyncProjectEventListenerAdapter.getProjectMapping(project);
JMSMessageListener jmsMessageListener = jmsSyncProjectMapping.getJmsMessageListener();
// ACKNOWLEDGE LAST MMS MESSAGE TO CLEAR OWN QUEUE
Message lastMessage;
if (jmsMessageListener != null && (lastMessage = jmsMessageListener.getLastMessage()) != null) {
try {
lastMessage.acknowledge();
} catch (JMSException | IllegalStateException e) {
e.printStackTrace();
}
}
// NOTIFY OTHER USERS OF PROCESSED ELEMENTS
if (!deltaSyncRunner.getSuccessfulJmsChangelog().isEmpty()) {
ObjectNode teamworkCommittedMessage = JacksonUtils.getObjectMapper().createObjectNode();
teamworkCommittedMessage.put("source", "magicdraw");
teamworkCommittedMessage.put("sender", TicketUtils.getUsername());
teamworkCommittedMessage.set("synced", SyncElements.buildJson(deltaSyncRunner.getSuccessfulJmsChangelog()));
try {
TextMessage successfulTextMessage = jmsSyncProjectMapping.getSession().createTextMessage(JacksonUtils.getObjectMapper().writeValueAsString(teamworkCommittedMessage));
successfulTextMessage.setStringProperty(JMSUtils.MSG_SELECTOR_PROJECT_ID, Converters.getIProjectToIdConverter().apply(project.getPrimaryProject()));
successfulTextMessage.setStringProperty(JMSUtils.MSG_SELECTOR_REF_ID, MDUtils.getWorkspace(project) + "_mdk");
jmsSyncProjectMapping.getMessageProducer().send(successfulTextMessage);
int syncCount = deltaSyncRunner.getSuccessfulJmsChangelog().flattenedSize();
Application.getInstance().getGUILog().log("[INFO] Notified other clients of " + syncCount + " locally updated element" + (syncCount != 1 ? "s" : "") + ".");
} catch (JMSException | JsonProcessingException e) {
e.printStackTrace();
Application.getInstance().getGUILog().log("[ERROR] Failed to notify other clients of synced elements. This could result in redundant local updates.");
}
}
}
public static CoordinatedSyncProjectMapping getProjectMapping(Project project) {
CoordinatedSyncProjectMapping coordinatedSyncProjectMapping = projectMappings.get(project);
if (coordinatedSyncProjectMapping == null) {
projectMappings.put(project, coordinatedSyncProjectMapping = new CoordinatedSyncProjectMapping());
projectMappings.get(project).setDisabled(!project.isRemote());
}
return coordinatedSyncProjectMapping;
}
public DeltaSyncRunner getDeltaSyncRunner() {
return deltaSyncRunner;
}
public static class CoordinatedSyncProjectMapping {
private boolean disabled;
public synchronized boolean isDisabled() {
return (disabled || !MDKOptionsGroup.getMDKOptions().isCoordinatedSyncEnabled());
}
public synchronized void setDisabled(boolean disabled) {
this.disabled = disabled;
}
}
}