Skip to content

Commit 02ba95e

Browse files
committed
added bad state of notebook case, to recover
1 parent 7357d24 commit 02ba95e

File tree

8 files changed

+779
-52
lines changed

8 files changed

+779
-52
lines changed

nbcode/notebooks/nbproject/project.xml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,6 @@
5656
<specification-version>1.28</specification-version>
5757
</run-dependency>
5858
</dependency>
59-
<dependency>
60-
<code-name-base>org.netbeans.libs.javacapi</code-name-base>
61-
<build-prerequisite/>
62-
<compile-dependency/>
63-
<run-dependency>
64-
<implementation-version/>
65-
</run-dependency>
66-
</dependency>
67-
<dependency>
68-
<code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
69-
<build-prerequisite/>
70-
<compile-dependency/>
71-
<run-dependency>
72-
<release-version>1</release-version>
73-
<specification-version>1.65</specification-version>
74-
</run-dependency>
75-
</dependency>
7659
<dependency>
7760
<code-name-base>org.netbeans.modules.java.lsp.server</code-name-base>
7861
<build-prerequisite/>

nbcode/notebooks/src/org/netbeans/modules/nbcode/java/notebook/CellState.java

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515
*/
1616
package org.netbeans.modules.nbcode.java.notebook;
1717

18+
import java.util.concurrent.CompletableFuture;
19+
import java.util.concurrent.ExecutionException;
1820
import java.util.concurrent.atomic.AtomicReference;
21+
import java.util.logging.Logger;
1922
import org.eclipse.lsp4j.ExecutionSummary;
2023
import org.eclipse.lsp4j.NotebookCell;
2124
import org.eclipse.lsp4j.NotebookCellKind;
2225
import org.eclipse.lsp4j.TextDocumentItem;
26+
import org.netbeans.modules.java.lsp.server.notebook.CellStateResponse;
27+
import org.netbeans.modules.java.lsp.server.notebook.NotebookCellStateParams;
28+
import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient;
2329

2430
/**
2531
*
@@ -29,13 +35,18 @@ public class CellState {
2935

3036
private final NotebookCellKind type;
3137
private final String language;
38+
private final String cellUri;
39+
private final String notebookUri;
3240
private final AtomicReference<Object> metadata;
33-
private final AtomicReference<VersionAwareCotent> content;
41+
private final AtomicReference<VersionAwareContent> content;
3442
private final AtomicReference<ExecutionSummary> executionSummary;
43+
private static final Logger LOG = Logger.getLogger(CellState.class.getName());
3544

36-
CellState(NotebookCell notebookCell, TextDocumentItem details) {
45+
CellState(NotebookCell notebookCell, TextDocumentItem details, String notebookUri) {
3746
String normalizedText = NotebookUtils.normalizeLineEndings(details.getText());
38-
this.content = new AtomicReference<>(new VersionAwareCotent(normalizedText, details.getVersion()));
47+
this.cellUri = details.getUri();
48+
this.notebookUri = notebookUri;
49+
this.content = new AtomicReference<>(new VersionAwareContent(normalizedText, details.getVersion()));
3950
this.language = details.getLanguageId();
4051
this.type = notebookCell.getKind();
4152
this.metadata = new AtomicReference<>(notebookCell.getMetadata());
@@ -62,19 +73,57 @@ public ExecutionSummary getExecutionSummary() {
6273
return executionSummary.get();
6374
}
6475

65-
public void setContent(String newContent, int newVersion) {
76+
public String getCellUri() {
77+
return cellUri;
78+
}
79+
80+
public String getNotebookUri() {
81+
return notebookUri;
82+
}
83+
84+
public void setContent(String newContent, int newVersion) throws InterruptedException, ExecutionException {
6685
String normalizedContent = NotebookUtils.normalizeLineEndings(newContent);
67-
VersionAwareCotent currentContent = content.get();
86+
VersionAwareContent currentContent = content.get();
6887

6988
if (currentContent.getVersion() != newVersion - 1) {
70-
throw new IllegalStateException("Version mismatch: expected " + (newVersion - 1) + ", got " + currentContent.getVersion());
89+
if (currentContent.getVersion() >= newVersion) {
90+
LOG.warning("Current version is higher or equal than the new version request received, so ignoring it.");
91+
return;
92+
}
93+
CompletableFuture<CellStateResponse> response = requestLatestCellState();
94+
if (response == null) {
95+
throw new IllegalStateException("Unable to send notebook cell state request to the client");
96+
}
97+
98+
CellStateResponse newCellState = response.get();
99+
int receivedVersion = newCellState.getVersion();
100+
101+
if (receivedVersion > currentContent.getVersion()) {
102+
VersionAwareContent newVersionContent = new VersionAwareContent(newCellState.getText(), receivedVersion);
103+
content.set(newVersionContent);
104+
} else {
105+
throw new IllegalStateException("Version mismatch: Received version to be greater than current version, received version: " + (receivedVersion) + ", current version: " + currentContent.getVersion());
106+
}
107+
} else {
108+
VersionAwareContent newVersionContent = new VersionAwareContent(normalizedContent, newVersion);
109+
110+
if (!content.compareAndSet(currentContent, newVersionContent)) {
111+
throw new IllegalStateException("Concurrent modification detected. Version expected: " + (newVersion - 1) + ", current: " + content.get().getVersion());
112+
}
71113
}
114+
}
72115

73-
VersionAwareCotent newVersionContent = new VersionAwareCotent(normalizedContent, newVersion);
74-
75-
if (!content.compareAndSet(currentContent, newVersionContent)) {
76-
throw new IllegalStateException("Concurrent modification detected. Version expected: " + (newVersion - 1) + ", current: " + content.get().getVersion());
116+
public void requestContentAndSet() throws InterruptedException, ExecutionException {
117+
CompletableFuture<CellStateResponse> response = requestLatestCellState();
118+
if (response == null) {
119+
throw new IllegalStateException("Unable to send notebook cell state request to the client");
77120
}
121+
CellStateResponse newCellState = response.get();
122+
if (newCellState.getVersion() <= 0) {
123+
throw new IllegalStateException("Received incorrect version number: " + newCellState.getVersion());
124+
}
125+
VersionAwareContent newVersionContent = new VersionAwareContent(newCellState.getText(), newCellState.getVersion());
126+
content.set(newVersionContent);
78127
}
79128

80129
public void setExecutionSummary(ExecutionSummary executionSummary) {
@@ -85,12 +134,27 @@ public void setMetadata(Object metadata) {
85134
this.metadata.set(metadata);
86135
}
87136

88-
private class VersionAwareCotent {
137+
// protected methods for ease of unit testing
138+
protected CompletableFuture<CellStateResponse> requestLatestCellState() {
139+
NbCodeLanguageClient client = LanguageClientInstance.getInstance().getClient();
140+
141+
if (client == null) {
142+
LOG.warning("Client is null");
143+
return null;
144+
}
145+
return client.getNotebookCellState(new NotebookCellStateParams(notebookUri, cellUri));
146+
}
147+
148+
protected VersionAwareContent getVersionAwareContent(){
149+
return this.content.get();
150+
}
151+
152+
protected class VersionAwareContent {
89153

90154
private String content;
91155
private int version;
92156

93-
public VersionAwareCotent(String content, int version) {
157+
public VersionAwareContent(String content, int version) {
94158
this.content = content;
95159
this.version = version;
96160
}

nbcode/notebooks/src/org/netbeans/modules/nbcode/java/notebook/NotebookDocumentStateManager.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,17 @@ private void updateNotebookCellContent(NotebookDocumentChangeEventCellTextConten
150150
}
151151
int newVersion = contentChange.getDocument().getVersion();
152152
String currentContent = cellState.getContent();
153-
if (!contentChange.getChanges().isEmpty()) {
153+
154+
try {
155+
String updatedContent = applyContentChanges(currentContent, contentChange.getChanges());
156+
cellState.setContent(updatedContent, newVersion);
157+
LOG.log(Level.FINE, "Updated content for cell: {0}, version: {1}", new Object[]{uri, newVersion});
158+
} catch (Exception e) {
159+
LOG.log(Level.WARNING, "applyContentChanges failed, requesting full content: " + uri, e);
154160
try {
155-
String updatedContent = applyContentChanges(currentContent, contentChange.getChanges());
156-
cellState.setContent(updatedContent, newVersion);
157-
LOG.log(Level.FINE, "Updated content for cell: {0}, version: {1}", new Object[]{uri, newVersion});
158-
} catch (Exception e) {
159-
LOG.log(Level.SEVERE, "Failed to apply content changes to cell: " + uri, e);
160-
throw new RuntimeException("Failed to apply content changes", e);
161+
cellState.requestContentAndSet();
162+
} catch (Exception ex) {
163+
LOG.log(Level.SEVERE, "Failed to refresh content for cell: " + uri, ex);
161164
}
162165
}
163166
}
@@ -217,20 +220,24 @@ private String applyRangeChange(String content, TextDocumentContentChangeEvent c
217220

218221
return result.toString();
219222
}
220-
221-
private void addNewCellState(NotebookCell cell, TextDocumentItem item) {
223+
// protected methods for ease of unit testing
224+
protected void addNewCellState(NotebookCell cell, TextDocumentItem item) {
222225
if (cell == null || item == null) {
223226
LOG.log(Level.WARNING, "Attempted to add null cell or item");
224227
return;
225228
}
226229

227230
try {
228-
CellState cellState = new CellState(cell, item);
231+
CellState cellState = new CellState(cell, item, notebookDoc.getUri());
229232
cellsMap.put(item.getUri(), cellState);
230233
LOG.log(Level.FINE, "Added new cell state: {0}", item.getUri());
231234
} catch (Exception e) {
232235
LOG.log(Level.SEVERE, "Failed to create cell state for: " + item.getUri(), e);
233236
throw new RuntimeException("Failed to create cell state", e);
234237
}
235238
}
239+
240+
protected Map<String, CellState> getCellsMap(){
241+
return cellsMap;
242+
}
236243
}

0 commit comments

Comments
 (0)