Skip to content

Commit

Permalink
Merge pull request #3117 from ControlSystemStudio/CSSTUDIO-1650
Browse files Browse the repository at this point in the history
Compare snapshot to archiver data
  • Loading branch information
shroffk authored Aug 23, 2024
2 parents dd42fbe + b3468ac commit 31c437b
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 72 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions app/save-and-restore/app/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,22 @@ the :math:`{\Delta}` Base Snapshot column will show the difference to the refere
.. image:: images/compare-snapshots-view.png
:width: 80%

Compare to archiver data
------------------------

In the context menu of a tab showing a snapshot user can chose to compare the snapshot to data retrieved from an
archiver, if one is configured:

.. image:: images/compare_to_archiver.png

Selecting this item will trigger a date/time picker where user can specify the point in time for which to get
archiver data:

.. image:: images/date_time_picker.png

Once data has been returned from the archiver service, it will be rendered as a snapshot in the comparison view.

**NOTE:** If the archiver does not contain a PV, it will be rendered as DISCONNECTED in the view.

Search And Filters
------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class Messages {
public static String actionOpenNodeDescription;
public static String alertContinue;
public static String alertAddingPVsToConfiguration;
public static String archiver;
public static String authenticationFailed;
public static String baseSetpoint;
public static String buttonSearch;
Expand All @@ -38,6 +39,7 @@ public class Messages {
public static String contextMenuAddTagWithComment;
public static String contextMenuCreateSnapshot;
public static String contextMenuCompareSnapshots;
public static String contextMenuCompareSnapshotWithArchiverData;
public static String contextMenuDelete;
public static String copy;

Expand Down Expand Up @@ -65,6 +67,7 @@ public class Messages {
public static String currentPVValue;
public static String currentReadbackValue;
public static String currentSetpointValue;
public static String dateTimePickerTitle;
public static String deleteFilter;
public static String deleteFilterFailed;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Dialog;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
Expand Down Expand Up @@ -85,6 +86,7 @@
import org.phoebus.ui.dialog.DialogHelper;
import org.phoebus.ui.dialog.ExceptionDetailsErrorDialog;
import org.phoebus.ui.javafx.ImageCache;
import org.phoebus.ui.time.DateTimePane;

import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
Expand All @@ -95,6 +97,7 @@
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -385,6 +388,7 @@ protected void compareSnapshot() {
compareSnapshot(browserSelectionModel.getSelectedItems().get(0).getValue());
}


/**
* Action when user requests comparison between an opened snapshot and the specifies snapshot {@link Node}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package org.phoebus.applications.saveandrestore.ui;

import org.epics.vtype.VType;
import org.phoebus.applications.saveandrestore.model.*;
import org.phoebus.applications.saveandrestore.model.CompositeSnapshot;
import org.phoebus.applications.saveandrestore.model.Configuration;
Expand All @@ -35,8 +36,12 @@
import org.phoebus.applications.saveandrestore.client.SaveAndRestoreJerseyClient;

import org.phoebus.core.vtypes.VDisconnectedData;
import org.phoebus.pv.PV;
import org.phoebus.pv.PVPool;
import org.phoebus.util.time.TimestampFormats;

import javax.ws.rs.core.MultivaluedMap;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -419,6 +424,7 @@ public List<RestoreResult> restore(String snapshotNodeId) throws Exception{

/**
* Requests service to take a snapshot, i.e. to read PVs as defined in a {@link Configuration}.
* This should be called off the UI thread.
* @param configurationNodeId The unique id of the {@link Configuration} for which to take the snapshot
* @return A {@link List} of {@link SnapshotItem}s carrying snapshot values read by the service.
*/
Expand All @@ -427,4 +433,58 @@ public List<SnapshotItem> takeSnapshot(String configurationNodeId) throws Except
executor.submit(() -> saveAndRestoreClient.takeSnapshot(configurationNodeId));
return future.get();
}

/**
* Requests service to take a snapshot, i.e. to read PVs as defined in a {@link Configuration}.
* This should be called off the UI thread.
* @param configurationNodeId The unique id of the {@link Configuration} for which to take the snapshot
* @param time If non-null, the snapshot is created from archived values.
* @return A {@link List} of {@link SnapshotItem}s carrying snapshot values read by the service or read
* from an archiver.
*/
public List<SnapshotItem> takeSnapshot(String configurationNodeId, Instant time) throws Exception{
if(time == null){
return takeSnapshot(configurationNodeId);
}
else{
ConfigurationData configNode = getConfiguration(configurationNodeId);
List<ConfigPv> configPvList = configNode.getPvList();
List<SnapshotItem> snapshotItems = new ArrayList<>();
configPvList.forEach(configPv -> {
SnapshotItem snapshotItem = new SnapshotItem();
snapshotItem.setConfigPv(configPv);
snapshotItem.setValue(readFromArchiver(configPv.getPvName(), time));
if(configPv.getReadbackPvName() != null){
snapshotItem.setValue(readFromArchiver(configPv.getReadbackPvName(), time));
}
snapshotItems.add(snapshotItem);
});
return snapshotItems;
}
}

/**
* Reads the PV value from archiver.
* @param pvName Name of PV, scheme like for instance pva:// will be removed.
* @param time The point in time supplied in the archiver request
* @return A {@link VType} value if archiver contains the wanted data, otherwise {@link VDisconnectedData}.
*/
private VType readFromArchiver(String pvName, Instant time){
// Check if pv name is prefixed with a scheme, e.g. pva://, ca://...
int indexSchemeSeparator = pvName.indexOf("://");
if(indexSchemeSeparator > 0 && pvName.length() > indexSchemeSeparator){
pvName = pvName.substring(indexSchemeSeparator + 1);
}
// Prepend "alarm://"
pvName = "archive://" + pvName + "(" + TimestampFormats.SECONDS_FORMAT.format(time) + ")";
try {
PV pv = PVPool.getPV(pvName);
VType pvValue = pv.read();
PVPool.releasePV(pv);
return pvValue;
} catch (Exception e) {
// Not found in archiver
return VDisconnectedData.INSTANCE;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import org.epics.vtype.*;
Expand All @@ -37,7 +38,9 @@
import org.phoebus.security.tokens.ScopedAuthenticationToken;
import org.phoebus.ui.dialog.DialogHelper;
import org.phoebus.ui.dialog.ExceptionDetailsErrorDialog;
import org.phoebus.ui.time.DateTimePane;

import java.time.Instant;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -378,16 +381,66 @@ private void showFailedRestoreResult(List<RestoreResult> restoreResultList){
});
}

/**
* Adds a snapshot for the sake of comparison with the one currently in view.
* @param snapshotNode A snapshot {@link Node} selected by user in the {@link javafx.scene.control.TreeView},
* i.e. a snapshot previously persisten in the service.
*/
public void addSnapshot(Node snapshotNode) {
disabledUi.set(true);
try {
Snapshot snapshot = getSnapshotFromService(snapshotNode);
snapshotTableViewController.addSnapshot(snapshot);
} catch (Exception e) {
Logger.getLogger(SnapshotController.class.getName()).log(Level.WARNING, "Failed to add snapshot", e);
} finally {
disabledUi.set(false);
JobManager.schedule("Add snapshot", monitor -> {
try {
Snapshot snapshot = getSnapshotFromService(snapshotNode);
Platform.runLater(() -> snapshotTableViewController.addSnapshot(snapshot));
} catch (Exception e) {
Logger.getLogger(SnapshotController.class.getName()).log(Level.WARNING, "Failed to add snapshot", e);
} finally {
disabledUi.set(false);
}
});
}

/**
* Launches a date/time picker and then reads from archiver to construct an in-memory {@link Snapshot} used for comparison.
* @param configurationNode A {@link Node} of type {@link NodeType#CONFIGURATION}.
*/
public void addSnapshotFromArchiver(Node configurationNode){
DateTimePane dateTimePane = new DateTimePane();
Dialog<Instant> timePickerDialog = new Dialog<>();
timePickerDialog.setTitle(Messages.dateTimePickerTitle);
timePickerDialog.getDialogPane().setContent(dateTimePane);
timePickerDialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
timePickerDialog.setResultConverter(b -> {
if(b.equals(ButtonType.OK)){
return dateTimePane.getInstant();
}
return null;
});
Instant time = timePickerDialog.showAndWait().get();
if(time == null){ // User cancels date/time picker dialog
return;
}
disabledUi.set(true);
JobManager.schedule("Add snapshot from archiver", monitor -> {
List<SnapshotItem> snapshotItems;
try {
snapshotItems = SaveAndRestoreService.getInstance().takeSnapshot(configurationNode.getUniqueId(), time);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to query archiver for data", e);
disabledUi.set(false);
return;
}
Snapshot snapshot = new Snapshot();
snapshot.setSnapshotNode(Node.builder().nodeType(NodeType.SNAPSHOT).name(Messages.archiver).created(new Date(time.toEpochMilli())).build());
SnapshotData snapshotData = new SnapshotData();
snapshotData.setUniqueId("anonymous");
snapshotData.setSnapshotItems(snapshotItems);
snapshot.setSnapshotData(snapshotData);
Platform.runLater(() -> {
snapshotTableViewController.addSnapshot(snapshot);
disabledUi.set(false);
});
});
}

private Snapshot getSnapshotFromService(Node snapshotNode) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import org.phoebus.applications.saveandrestore.model.NodeType;
import org.phoebus.applications.saveandrestore.model.event.SaveAndRestoreEventReceiver;
import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreBaseController;
import org.phoebus.pv.PV;
import org.phoebus.pv.PVPool;
import org.phoebus.ui.docking.DockPane;
import org.phoebus.util.time.TimestampFormats;

Expand Down
Loading

0 comments on commit 31c437b

Please sign in to comment.