Skip to content

Commit 4e33a47

Browse files
committed
Find referenced snapshots, UI parts and server fixes
1 parent d9cd17f commit 4e33a47

File tree

12 files changed

+178
-114
lines changed

12 files changed

+178
-114
lines changed

app/save-and-restore/app/doc/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ Brief description of all items in the context menu (details on actions are outli
8888
* Restore from client - restore a snapshot or composite snapshot from the client application.
8989
* Restore from service - restore a snapshot or composite snapshot from the service.
9090
* Edit - edit a configuration.
91-
* Rename - rename a folder or configuration.
91+
* Find references - locates composite snapshot nodes referencing the selected node.
92+
* Rename - rename a folder.
9293
* Copy - put selected items on clipboard.
9394
* Paste - paste items from clipboard.
9495
* Delete - delete selected items.

app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/SaveAndRestoreController.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import org.phoebus.applications.saveandrestore.ui.contextmenu.CreateSnapshotMenuItem;
8787
import org.phoebus.applications.saveandrestore.ui.contextmenu.EditCompositeMenuItem;
8888
import org.phoebus.applications.saveandrestore.ui.contextmenu.ExportToCSVMenuItem;
89+
import org.phoebus.applications.saveandrestore.ui.contextmenu.FindReferencesMenuItem;
8990
import org.phoebus.applications.saveandrestore.ui.contextmenu.ImportFromCSVMenuItem;
9091
import org.phoebus.applications.saveandrestore.ui.contextmenu.LoginMenuItem;
9192
import org.phoebus.applications.saveandrestore.ui.contextmenu.NewCompositeSnapshotMenuItem;
@@ -232,6 +233,7 @@ public class SaveAndRestoreController extends SaveAndRestoreBaseController
232233
}),
233234
new SeparatorMenuItem(),
234235
new EditCompositeMenuItem(this, selectedItemsProperty, this::editCompositeSnapshot),
236+
new FindReferencesMenuItem(this, selectedItemsProperty, this::findReferences),
235237
new RenameFolderMenuItem(this, selectedItemsProperty, this::renameNode),
236238
copyMenuItem,
237239
pasteMenuItem,
@@ -525,7 +527,7 @@ private void deleteTreeItems(ObservableList<TreeItem<Node>> items) {
525527
/**
526528
* Opens a new snapshot view tab associated with the selected configuration.
527529
*/
528-
public void openConfigurationForSnapshot() {
530+
private void openConfigurationForSnapshot() {
529531
TreeItem<Node> treeItem = browserSelectionModel.getSelectedItems().get(0);
530532
SnapshotTab tab = new SnapshotTab(treeItem.getValue(), saveAndRestoreService);
531533
tab.newSnapshot(treeItem.getValue());
@@ -634,7 +636,7 @@ public void nodeDoubleClicked(Node node) {
634636
* Launches the composite snapshot editor view. Note that a tab showing this view uses the "edit_" prefix
635637
* for the id since it would otherwise clash with a restore view of a composite snapshot.
636638
*/
637-
public void editCompositeSnapshot() {
639+
private void editCompositeSnapshot() {
638640
Node compositeSnapshotNode = browserSelectionModel.getSelectedItem().getValue();
639641
editCompositeSnapshot(compositeSnapshotNode, Collections.emptyList());
640642
}
@@ -709,11 +711,11 @@ private Tab getTab(String id) {
709711
/**
710712
* Creates a new configuration in the selected tree node.
711713
*/
712-
public void createNewConfiguration() {
714+
private void createNewConfiguration() {
713715
launchTabForNewConfiguration(browserSelectionModel.getSelectedItems().get(0).getValue());
714716
}
715717

716-
public void createNewCompositeSnapshot() {
718+
private void createNewCompositeSnapshot() {
717719
launchTabForNewCompositeSnapshot(browserSelectionModel.getSelectedItems().get(0).getValue(),
718720
Collections.emptyList());
719721
}
@@ -1506,4 +1508,9 @@ public boolean doCloseCheck(){
15061508
}
15071509
return true;
15081510
}
1511+
1512+
private void findReferences(){
1513+
SearchAndFilterTab searchAndFilterTab = openSearchWindow();
1514+
searchAndFilterTab.getController().findReferencesForSnapshot(treeView.getSelectionModel().getSelectedItems().get(0).getValue().getUniqueId());
1515+
}
15091516
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (C) 2024 European Spallation Source ERIC.
3+
*/
4+
5+
package org.phoebus.applications.saveandrestore.ui.contextmenu;
6+
7+
import javafx.collections.ObservableList;
8+
import org.phoebus.applications.saveandrestore.Messages;
9+
import org.phoebus.applications.saveandrestore.model.Node;
10+
import org.phoebus.applications.saveandrestore.model.NodeType;
11+
import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreBaseController;
12+
import org.phoebus.ui.javafx.ImageCache;
13+
14+
/**
15+
* {@link javafx.scene.control.MenuItem} for finding references of a snapshot or composite snapshot.
16+
*/
17+
public class FindReferencesMenuItem extends SaveAndRestoreMenuItem {
18+
19+
public FindReferencesMenuItem(SaveAndRestoreBaseController saveAndRestoreController,
20+
ObservableList<Node> selectedItemsProperty,
21+
Runnable onAction) {
22+
super(saveAndRestoreController, selectedItemsProperty, onAction);
23+
setGraphic(ImageCache.getImageView(ImageCache.class, "/icons/sar-search_18x18.png"));
24+
setText(Messages.findSnapshotReferences);
25+
}
26+
27+
@Override
28+
public void configure() {
29+
visibleProperty().set(selectedItemsProperty.size() == 1 &&
30+
(selectedItemsProperty.get(0).getNodeType().equals(NodeType.SNAPSHOT) ||
31+
selectedItemsProperty.get(0).getNodeType().equals(NodeType.COMPOSITE_SNAPSHOT)));
32+
}
33+
}

app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/search/SearchAndFilterTab.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.phoebus.applications.saveandrestore.Messages;
2626
import org.phoebus.applications.saveandrestore.SaveAndRestoreApplication;
2727
import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreController;
28-
import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreService;
2928
import org.phoebus.applications.saveandrestore.ui.SaveAndRestoreTab;
3029
import org.phoebus.framework.nls.NLS;
3130
import org.phoebus.ui.javafx.ImageCache;
@@ -65,7 +64,7 @@ public SearchAndFilterTab(SaveAndRestoreController saveAndRestoreController) {
6564
Node node = loader.load();
6665
controller = loader.getController();
6766
setContent(node);
68-
setOnCloseRequest(event -> ((SearchAndFilterViewController)controller).handleSaveAndFilterTabClosed());
67+
setOnCloseRequest(event -> ((SearchAndFilterViewController) controller).handleSaveAndFilterTabClosed());
6968
} catch (IOException e) {
7069
Logger.getLogger(SearchAndFilterTab.class.getName())
7170
.log(Level.SEVERE, "Unable to load search tab content fxml", e);
@@ -75,4 +74,8 @@ public SearchAndFilterTab(SaveAndRestoreController saveAndRestoreController) {
7574
setText(Messages.search);
7675
setGraphic(new ImageView(ImageCache.getImage(ImageCache.class, "/icons/sar-search_18x18.png")));
7776
}
77+
78+
public SearchAndFilterViewController getController() {
79+
return (SearchAndFilterViewController) controller;
80+
}
7881
}

app/save-and-restore/app/src/main/java/org/phoebus/applications/saveandrestore/ui/search/SearchAndFilterViewController.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ public class SearchAndFilterViewController extends SaveAndRestoreBaseController
208208

209209
private final SimpleBooleanProperty goldenOnlyProperty = new SimpleBooleanProperty();
210210

211+
private final SimpleStringProperty referencedProperty = new SimpleStringProperty();
212+
211213
private static final Logger LOGGER = Logger.getLogger(SearchAndFilterViewController.class.getName());
212214

213215
private final SimpleBooleanProperty disableUi = new SimpleBooleanProperty();
@@ -534,6 +536,9 @@ private String buildQueryString() {
534536
map.put(Keys.TAGS.getName(), tags + "," + Tag.GOLDEN);
535537
}
536538
}
539+
if (referencedProperty.get() != null && !referencedProperty.get().trim().isEmpty()) {
540+
map.put(Keys.REFERENCED.getName(), referencedProperty.get());
541+
}
537542
return SearchQueryUtil.toQueryString(map);
538543
}
539544

@@ -649,12 +654,17 @@ public void handleWebSocketMessage(SaveAndRestoreWebSocketMessage<?> saveAndRest
649654
}
650655

651656
@Override
652-
public void handleTabClosed(){
657+
public void handleTabClosed() {
653658
webSocketClientService.removeWebSocketMessageHandler(this);
654659
}
655660

656661
@Override
657-
public boolean doCloseCheck(){
662+
public boolean doCloseCheck() {
658663
return true;
659664
}
665+
666+
public void findReferencesForSnapshot(String nodeId) {
667+
referencedProperty.setValue(nodeId);
668+
updateParametersAndSearch();
669+
}
660670
}

app/save-and-restore/model/src/main/java/org/phoebus/applications/saveandrestore/model/search/SearchQueryUtil.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public enum Keys {
4141
FROM("from"),
4242
SIZE("size"),
4343
GOLDEN("golden"),
44-
PVS("pvs");
44+
PVS("pvs"),
45+
REFERENCED("referenced");
4546

4647
private final String name;
4748

@@ -58,7 +59,7 @@ public String toString() {
5859
return getName();
5960
}
6061

61-
protected static final Map<String, Keys> lookupTable = new HashMap<>();
62+
private static final Map<String, Keys> lookupTable = new HashMap<>();
6263

6364
static {
6465
lookupTable.put("name", Keys.NAME);
@@ -70,6 +71,7 @@ public String toString() {
7071
lookupTable.put("type", Keys.TYPE);
7172
lookupTable.put("golden", Keys.GOLDEN);
7273
lookupTable.put("pvs", Keys.PVS);
74+
lookupTable.put("referenced", Keys.REFERENCED);
7375
}
7476

7577
public static Keys findKey(String keyName) {

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/persistence/dao/NodeDAO.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,6 @@ public interface NodeDAO {
6363
*/
6464
List<Node> getNodes(List<String> uniqueNodeIds);
6565

66-
/**
67-
* This is deprecated, use {@link #deleteNodes} instead.
68-
*
69-
* @param nodeId The unique id of the node to delete.
70-
*/
71-
void deleteNode(String nodeId);
7266

7367
/**
7468
* Checks that each of the node ids passed to this method exist, and that none of them

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/persistence/dao/impl/elasticsearch/CompositeSnapshotDataRepository.java

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import co.elastic.clients.elasticsearch._types.Refresh;
2323
import co.elastic.clients.elasticsearch._types.Result;
2424
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
25-
import co.elastic.clients.elasticsearch._types.query_dsl.MatchPhraseQuery;
2625
import co.elastic.clients.elasticsearch.core.CountRequest;
2726
import co.elastic.clients.elasticsearch.core.CountResponse;
2827
import co.elastic.clients.elasticsearch.core.DeleteByQueryRequest;
@@ -37,10 +36,11 @@
3736
import co.elastic.clients.elasticsearch.core.SearchRequest;
3837
import co.elastic.clients.elasticsearch.core.SearchResponse;
3938
import co.elastic.clients.elasticsearch.core.search.Hit;
39+
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
4040
import co.elastic.clients.transport.endpoints.BooleanResponse;
41-
import org.elasticsearch.action.search.SearchRequestBuilder;
42-
import org.phoebus.applications.saveandrestore.model.CompositeSnapshot;
4341
import org.phoebus.applications.saveandrestore.model.CompositeSnapshotData;
42+
import org.phoebus.applications.saveandrestore.model.Node;
43+
import org.phoebus.applications.saveandrestore.model.search.SearchResult;
4444
import org.phoebus.service.saveandrestore.model.ESTreeNode;
4545
import org.phoebus.service.saveandrestore.search.SearchUtil;
4646
import org.springframework.beans.factory.annotation.Autowired;
@@ -70,6 +70,9 @@ public class CompositeSnapshotDataRepository implements CrudRepository<Composite
7070
@Value("${elasticsearch.composite_snapshot_node.index:saveandrestore_composite_snapshot}")
7171
private String ES_COMPOSITE_SNAPSHOT_INDEX;
7272

73+
@Autowired
74+
private ElasticsearchTreeRepository elasticsearchTreeRepository;
75+
7376
@Autowired
7477
@Qualifier("client")
7578
ElasticsearchClient client;
@@ -145,19 +148,20 @@ public boolean existsById(String s) {
145148
* Retrieves all {@link CompositeSnapshotData} documents. Note that to work around the limits in
146149
* Elasticsearch (e.g. max 10000 documents in a search request), the implementation uses paginated search to repeatedly
147150
* query for next round of hits. A page size of 100 is used for each query.
151+
*
148152
* @return An {@link Iterable} of {@link CompositeSnapshotData} objects, potentially empty.
149153
*/
150154
@Override
151-
public Iterable<CompositeSnapshotData> findAll() {
155+
public Iterable<CompositeSnapshotData> findAll() {
152156
List<CompositeSnapshotData> result = new ArrayList<>();
153157
int pageSize = 100;
154158
int from = 0;
155-
while(true){
159+
while (true) {
156160
try {
157161
SearchResponse<CompositeSnapshotData> searchResponse = runPagedMatchAll(pageSize, from);
158162
result.addAll(searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList()));
159163
from += searchResponse.hits().hits().size();
160-
if(searchResponse.hits().hits().size() < pageSize){
164+
if (searchResponse.hits().hits().size() < pageSize) {
161165
break;
162166
}
163167
} catch (IOException e) {
@@ -168,13 +172,13 @@ public Iterable<CompositeSnapshotData> findAll() {
168172
return result;
169173
}
170174

171-
private SearchResponse<CompositeSnapshotData> runPagedMatchAll(int pageSize, int from) throws IOException{
175+
private SearchResponse<CompositeSnapshotData> runPagedMatchAll(int pageSize, int from) throws IOException {
172176
SearchRequest searchRequest =
173177
SearchRequest.of(s ->
174-
s.index(ES_COMPOSITE_SNAPSHOT_INDEX)
175-
.query(new MatchAllQuery.Builder().build()._toQuery())
176-
.size(pageSize)
177-
.from(from));
178+
s.index(ES_COMPOSITE_SNAPSHOT_INDEX)
179+
.query(new MatchAllQuery.Builder().build()._toQuery())
180+
.size(pageSize)
181+
.from(from));
178182
return client.search(searchRequest, CompositeSnapshotData.class);
179183
}
180184

@@ -185,14 +189,13 @@ public Iterable<CompositeSnapshotData> findAllById(Iterable<String> strings) {
185189

186190
@Override
187191
public long count() {
188-
try{
192+
try {
189193
CountRequest countRequest = CountRequest.of(c ->
190194
c.index(ES_COMPOSITE_SNAPSHOT_INDEX));
191195
CountResponse countResponse = client.count(countRequest);
192196
return countResponse.count();
193-
}
194-
catch(Exception e){
195-
logger.log(Level.SEVERE, "Failed to count CompositeSnapshot objects" , e);
197+
} catch (Exception e) {
198+
logger.log(Level.SEVERE, "Failed to count CompositeSnapshot objects", e);
196199
throw new RuntimeException(e);
197200
}
198201
}
@@ -203,10 +206,9 @@ public void deleteById(String s) {
203206
DeleteRequest deleteRequest = DeleteRequest.of(d ->
204207
d.index(ES_COMPOSITE_SNAPSHOT_INDEX).id(s).refresh(Refresh.True));
205208
DeleteResponse deleteResponse = client.delete(deleteRequest);
206-
if(deleteResponse.result().equals(Result.Deleted)){
209+
if (deleteResponse.result().equals(Result.Deleted)) {
207210
logger.log(Level.WARNING, "Composite snapshot with id " + s + " deleted.");
208-
}
209-
else{
211+
} else {
210212
logger.log(Level.WARNING, "Composite snapshot with id " + s + " NOT deleted.");
211213
}
212214
} catch (IOException e) {
@@ -243,12 +245,24 @@ public void deleteAll() {
243245
}
244246
}
245247

246-
public List<CompositeSnapshotData> containedIn(MultiValueMap<String, String> searchParameters){
248+
/**
249+
* Finds {@link Node}s of type {@link org.phoebus.applications.saveandrestore.model.NodeType#COMPOSITE_SNAPSHOT} referencing
250+
* the node id present in the search parameters.
251+
*
252+
* @param searchParameters {@link MultiValueMap} that should contain an element keyed &quot;referenced&quot;
253+
* @return A potentially empty {@link SearchResult}
254+
*/
255+
public SearchResult referenced(MultiValueMap<String, String> searchParameters) {
247256

248257
SearchRequest searchRequest = searchUtil.buildSearchRequest(searchParameters);
249258
try {
250259
SearchResponse<CompositeSnapshotData> response = client.search(searchRequest, CompositeSnapshotData.class);
251-
return response.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
260+
HitsMetadata<CompositeSnapshotData> hitsMetadata = response.hits();
261+
List<CompositeSnapshotData> compositeSnapshotDataList = hitsMetadata.hits().stream().map(Hit::source).toList();
262+
Iterable<ESTreeNode> esTreeNodes = elasticsearchTreeRepository.findAllById(compositeSnapshotDataList.stream().map(CompositeSnapshotData::getUniqueId).toList());
263+
List<Node> list = new ArrayList<>();
264+
esTreeNodes.iterator().forEachRemaining(es -> list.add(es.getNode()));
265+
return new SearchResult((int) hitsMetadata.total().value(), list);
252266
} catch (IOException e) {
253267
logger.log(Level.SEVERE, "Failed to search for referenced snapshot nodes", e);
254268
throw new RuntimeException(e);

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/persistence/dao/impl/elasticsearch/ElasticsearchDAO.java

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,6 @@ public List<Node> getNodes(List<String> uniqueNodeIds) {
127127
return nodes;
128128
}
129129

130-
/**
131-
* {@inheritDoc}
132-
*/
133-
@Override
134-
@Deprecated
135-
public void deleteNode(String nodeId) {
136-
deleteNodes(List.of(nodeId));
137-
}
138-
139130
/**
140131
* {@inheritDoc}
141132
*/
@@ -1113,7 +1104,15 @@ private SearchResult searchInternal(MultiValueMap<String, String> searchParamete
11131104
augmented.putAll(searchParameters);
11141105
augmented.put("uniqueid", uniqueIds);
11151106
return elasticsearchTreeRepository.search(augmented);
1116-
} else {
1107+
}
1108+
// Did client specify search for references of a node?
1109+
else if(searchParameters.keySet().stream().anyMatch(k -> k.strip().toLowerCase().contains("referenced"))){
1110+
if(searchParameters.get("referenced").isEmpty()){
1111+
return new SearchResult(0, Collections.emptyList());
1112+
}
1113+
return compositeSnapshotDataRepository.referenced(searchParameters);
1114+
}
1115+
else {
11171116
return elasticsearchTreeRepository.search(searchParameters);
11181117
}
11191118
}
@@ -1289,16 +1288,4 @@ public int compare(String s1, String s2) {
12891288
return index1 - index2;
12901289
}
12911290
}
1292-
1293-
public List<Node> containedInCompositeSnapshot(MultiValueMap<String, String> searchParameters){
1294-
List<CompositeSnapshotData> compositeSnapshotDataList = compositeSnapshotDataRepository.containedIn(searchParameters);
1295-
List<String> compositeSnapshotIds = compositeSnapshotDataList.stream().map(CompositeSnapshotData::getUniqueId).toList();
1296-
1297-
Iterable<ESTreeNode> esTreeNodes = elasticsearchTreeRepository.findAllById(compositeSnapshotIds);
1298-
1299-
List<Node> list = new ArrayList<>();
1300-
esTreeNodes.iterator().forEachRemaining(es -> list.add(es.getNode()));
1301-
1302-
return list;
1303-
}
13041291
}

0 commit comments

Comments
 (0)