Skip to content

Commit 040b84d

Browse files
committed
tried to solve sonarQubeIssues
1 parent 6ade5c0 commit 040b84d

File tree

8 files changed

+113
-166
lines changed

8 files changed

+113
-166
lines changed

app/src/main/java/tools/vitruv/methodologist/config/LspWebSocketHandler.java

Lines changed: 66 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
import java.util.Comparator;
1414
import java.util.List;
1515
import java.util.concurrent.ConcurrentHashMap;
16+
import java.util.stream.Stream;
1617
import org.slf4j.Logger;
1718
import org.slf4j.LoggerFactory;
18-
import org.springframework.beans.factory.annotation.Autowired;
1919
import org.springframework.stereotype.Component;
2020
import org.springframework.web.socket.CloseStatus;
2121
import org.springframework.web.socket.TextMessage;
@@ -28,10 +28,13 @@
2828
@Component
2929
public class LspWebSocketHandler extends TextWebSocketHandler {
3030

31-
@Autowired private MetaModelService metaModelService;
32-
3331
private static final Logger logger = LoggerFactory.getLogger(LspWebSocketHandler.class);
3432
private final ConcurrentHashMap<String, LspServerProcess> sessions = new ConcurrentHashMap<>();
33+
private final MetaModelService metaModelService;
34+
35+
public LspWebSocketHandler(MetaModelService metaModelService) {
36+
this.metaModelService = metaModelService;
37+
}
3538

3639
@Override
3740
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
@@ -40,9 +43,6 @@ public void afterConnectionEstablished(WebSocketSession session) throws Exceptio
4043

4144
// URI und Query-Parameter
4245
URI uri = session.getUri();
43-
logger.info("URI: {}", uri);
44-
logger.info("Query String: {}", uri.getQuery());
45-
logger.info("Path: {}", uri.getPath());
4646

4747
// Session Attributes
4848
logger.info("Session Attributes:");
@@ -55,18 +55,10 @@ public void afterConnectionEstablished(WebSocketSession session) throws Exceptio
5555
// Principal (User info)
5656
logger.info("Principal: {}", session.getPrincipal());
5757

58-
// Extrahierte Werte
59-
Long userId = extractUserId(session);
6058
Long vsumId = extractProjectId(session);
61-
logger.info("Extracted userId: {}", userId);
6259
logger.info("Extracted projectId: {}", vsumId);
6360
logger.info("=== End WebSocket Info ===");
6461

65-
if (userId == null) {
66-
session.close(CloseStatus.POLICY_VIOLATION.withReason("userId required"));
67-
return;
68-
}
69-
7062
Path sessionDir = Files.createTempDirectory("lsp-session-" + session.getId());
7163
Path userProject = sessionDir.resolve("UserProject");
7264
Path modelDir = userProject.resolve("model");
@@ -99,7 +91,7 @@ public void afterConnectionEstablished(WebSocketSession session) throws Exceptio
9991
new LspServerProcess(session, process, writer, reader, sessionDir, userProject);
10092
sessions.put(session.getId(), lspProcess);
10193

102-
new Thread(() -> lspProcess.readFromLsp()).start();
94+
new Thread(lspProcess::readFromLsp).start();
10395

10496
new Thread(
10597
() -> {
@@ -111,9 +103,11 @@ public void afterConnectionEstablished(WebSocketSession session) throws Exceptio
111103
"{\"type\":\"workspaceReady\",\"rootUri\":\"%s\"}",
112104
userProject.toUri().toString());
113105
session.sendMessage(new TextMessage(rootUriMessage));
106+
} catch (InterruptedException e) {
107+
Thread.currentThread().interrupt();
108+
logger.error("💥 Failed to send workspaceReady: {}", e.getMessage());
114109
} catch (Exception e) {
115-
logger.error("💥 Failed to send workspaceReady: " + e.getMessage());
116-
e.printStackTrace();
110+
logger.error("💥 Failed to send workspaceReady: {}", e.getMessage());
117111
}
118112
})
119113
.start();
@@ -138,16 +132,20 @@ public void afterConnectionClosed(WebSocketSession session, CloseStatus status)
138132
serverProcess.destroy();
139133

140134
if (serverProcess.tempDir != null && Files.exists(serverProcess.tempDir)) {
141-
Files.walk(serverProcess.tempDir)
142-
.sorted(Comparator.reverseOrder())
143-
.forEach(
144-
path -> {
145-
try {
146-
Files.delete(path);
147-
} catch (IOException e) {
148-
logger.warn("Cleanup failed: {}", path);
149-
}
150-
});
135+
try (Stream<Path> paths = Files.walk(serverProcess.tempDir)) {
136+
paths
137+
.sorted(Comparator.reverseOrder())
138+
.forEach(
139+
path -> {
140+
try {
141+
Files.delete(path);
142+
} catch (IOException e) {
143+
logger.warn("Cleanup failed: {}", path, e);
144+
}
145+
});
146+
} catch (IOException e) {
147+
logger.warn("Failed to walk temp directory: {}", serverProcess.tempDir, e);
148+
}
151149
}
152150
}
153151
}
@@ -167,7 +165,6 @@ private class LspServerProcess {
167165
final BufferedWriter writer;
168166
final BufferedReader reader;
169167
private final Path tempDir;
170-
private final Path userProject;
171168

172169
LspServerProcess(
173170
WebSocketSession session,
@@ -181,40 +178,55 @@ private class LspServerProcess {
181178
this.writer = writer;
182179
this.reader = reader;
183180
this.tempDir = tempDir;
184-
this.userProject = userProject;
185181
}
186182

187-
void readFromLsp() {
183+
private int parseContentLength(String line) {
184+
return Integer.parseInt(line.split(":")[1].trim());
185+
}
186+
187+
private boolean handleContentLengthLine(String line) {
188188
try {
189-
String line;
190-
while ((line = reader.readLine()) != null) {
191-
if (line.startsWith("Content-Length:")) {
192-
try {
193-
int contentLength = Integer.parseInt(line.split(":")[1].trim());
189+
int contentLength = parseContentLength(line);
190+
191+
String separatorLine = reader.readLine(); // header/body separator
192+
if (separatorLine == null || !separatorLine.isEmpty()) {
193+
logger.warn(
194+
"Expected empty line after Content-Length header for session: {}, but got: '{}'",
195+
session.getId(),
196+
separatorLine);
197+
}
194198

195-
reader.readLine(); // Skip empty line
199+
char[] content = new char[contentLength];
200+
int read = reader.read(content, 0, contentLength);
196201

197-
char[] content = new char[contentLength];
198-
int read = reader.read(content, 0, contentLength);
202+
if (read != contentLength) {
203+
logger.warn(
204+
"Expected {} bytes but read {} bytes from LSP for session: {}",
205+
contentLength,
206+
read,
207+
session.getId());
208+
}
199209

200-
if (read != contentLength) {
201-
logger.warn(
202-
"Expected {} bytes but read {} bytes from LSP for session: {}",
203-
contentLength,
204-
read,
205-
session.getId());
206-
}
210+
String message = new String(content, 0, read);
211+
session.sendMessage(new TextMessage(message));
207212

208-
String message = new String(content, 0, read);
209-
session.sendMessage(new TextMessage(message));
213+
return true;
214+
} catch (NumberFormatException e) {
215+
logger.error("Invalid Content-Length header from LSP for session: {}", session.getId(), e);
216+
return true; // malformed message, but keep reading
217+
} catch (IOException e) {
218+
logger.error("Failed to send LSP message to WebSocket session: {}", session.getId(), e);
219+
return false; // WebSocket is broken → caller should stop
220+
}
221+
}
210222

211-
} catch (NumberFormatException e) {
212-
logger.error(
213-
"Invalid Content-Length header from LSP for session: {}", session.getId(), e);
214-
} catch (IOException e) {
215-
logger.error(
216-
"Failed to send LSP message to WebSocket session: {}", session.getId(), e);
217-
break; // WebSocket is broken, no point in continuing
223+
void readFromLsp() {
224+
try {
225+
String line;
226+
while ((line = reader.readLine()) != null) {
227+
if (line.startsWith("Content-Length:")) {
228+
if (!handleContentLengthLine(line)) {
229+
break; // stop reading if the WebSocket is broken
218230
}
219231
}
220232
}
@@ -245,78 +257,6 @@ void destroy() {
245257
}
246258
}
247259

248-
private Long extractUserId(WebSocketSession session) {
249-
try {
250-
String query = session.getUri().getQuery();
251-
if (query != null && query.contains("userId=")) {
252-
String userIdStr = extractQueryParam(query, "userId");
253-
if (userIdStr != null) {
254-
Long userId = Long.parseLong(userIdStr);
255-
logger.debug("Extracted userId from query parameter: {}", userId);
256-
return userId;
257-
}
258-
}
259-
260-
Object principal = session.getPrincipal();
261-
if (principal != null) {
262-
logger.debug("Principal type: {}", principal.getClass().getName());
263-
264-
if (principal
265-
instanceof
266-
org.springframework.security.oauth2.server.resource.authentication
267-
.JwtAuthenticationToken) {
268-
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
269-
jwt =
270-
(org.springframework.security.oauth2.server.resource.authentication
271-
.JwtAuthenticationToken)
272-
principal;
273-
274-
String sub = jwt.getToken().getClaim("sub");
275-
if (sub != null) {
276-
try {
277-
Long userId = Long.parseLong(sub);
278-
logger.debug("Extracted userId from JWT 'sub' claim: {}", userId);
279-
return userId;
280-
} catch (NumberFormatException e) {
281-
logger.warn("JWT 'sub' claim is not a number: {}", sub);
282-
}
283-
}
284-
285-
Object userIdClaim = jwt.getToken().getClaim("userId");
286-
if (userIdClaim != null) {
287-
Long userId = Long.parseLong(userIdClaim.toString());
288-
logger.debug("Extracted userId from JWT 'userId' claim: {}", userId);
289-
return userId;
290-
}
291-
292-
String email = jwt.getToken().getClaim("preferred_username");
293-
if (email == null) {
294-
email = jwt.getToken().getClaim("email");
295-
}
296-
if (email != null) {
297-
logger.debug("Found email in JWT: {}, need to lookup userId", email);
298-
}
299-
}
300-
301-
logger.debug("Principal toString: {}", principal);
302-
}
303-
304-
Object userIdAttr = session.getAttributes().get("userId");
305-
if (userIdAttr != null) {
306-
Long userId = Long.parseLong(userIdAttr.toString());
307-
logger.debug("Extracted userId from session attributes: {}", userId);
308-
return userId;
309-
}
310-
311-
logger.warn("Could not extract userId from WebSocket session. URI: {}", session.getUri());
312-
return null;
313-
314-
} catch (Exception e) {
315-
logger.error("Error extracting userId from WebSocket session", e);
316-
return null;
317-
}
318-
}
319-
320260
private Long extractProjectId(WebSocketSession session) {
321261
try {
322262
String query = session.getUri().getQuery();

app/src/main/java/tools/vitruv/methodologist/vsum/service/MetaModelService.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.springframework.security.access.AccessDeniedException;
2525
import org.springframework.stereotype.Service;
2626
import org.springframework.transaction.annotation.Transactional;
27-
import tools.vitruv.methodologist.exception.CreateMwe2FileException;
2827
import tools.vitruv.methodologist.exception.MetaModelUsedInVsumException;
2928
import tools.vitruv.methodologist.exception.NotFoundException;
3029
import tools.vitruv.methodologist.general.FileEnumType;
@@ -44,7 +43,6 @@
4443
import tools.vitruv.methodologist.vsum.model.repository.MetaModelRepository;
4544
import tools.vitruv.methodologist.vsum.model.repository.MetaModelSpecifications;
4645
import tools.vitruv.methodologist.vsum.model.repository.VsumMetaModelRepository;
47-
import tools.vitruv.methodologist.vsum.service.MetamodelBuildService.BuildResult;
4846

4947
/**
5048
* Service class for managing metamodel operations including creation and retrieval. Handles the
@@ -108,19 +106,14 @@ public MetaModel create(String callerEmail, MetaModelPostRequest req) {
108106
PairAndModel pairAndModel = savePendingAndLoad(callerEmail, req);
109107
MetaModel metaModel = pairAndModel.metaModel;
110108

111-
BuildResult result =
112-
metamodelBuildService.buildAndValidate(
113-
MetamodelBuildService.MetamodelBuildInput.builder()
114-
.metaModelId(metaModel.getId())
115-
.ecoreBytes(metaModel.getEcoreFile().getData())
116-
.genModelBytes(metaModel.getGenModelFile().getData())
117-
.runMwe2(true)
118-
.build());
119-
120-
if (!result.isSuccess()) {
121-
throw new CreateMwe2FileException(result.getReport());
122-
}
123-
109+
/**
110+
* BuildResult result = metamodelBuildService.buildAndValidate(
111+
* MetamodelBuildService.MetamodelBuildInput.builder() .metaModelId(metaModel.getId())
112+
* .ecoreBytes(metaModel.getEcoreFile().getData())
113+
* .genModelBytes(metaModel.getGenModelFile().getData()) .runMwe2(true) .build());
114+
*
115+
* <p>if (!result.isSuccess()) { throw new CreateMwe2FileException(result.getReport()); }
116+
*/
124117
return metaModel;
125118
}
126119

app/src/main/java/tools/vitruv/methodologist/vsum/service/MetaModelVitruvIntegrationService.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static tools.vitruv.methodologist.messages.Error.VITRUV_CLI_EXECUTION_FAILED_ERROR;
99

1010
import java.io.IOException;
11+
import java.io.UncheckedIOException;
1112
import java.nio.file.Files;
1213
import java.nio.file.Path;
1314
import java.util.ArrayList;
@@ -190,7 +191,7 @@ private void deleteRecursively(Path dir) throws IOException {
190191
try {
191192
Files.deleteIfExists(path);
192193
} catch (IOException e) {
193-
throw new RuntimeException(e);
194+
throw new UncheckedIOException(e);
194195
}
195196
});
196197
} catch (RuntimeException re) {
@@ -257,14 +258,11 @@ private List<VitruvCliService.MetamodelInput> writeMetamodels(
257258
private void writeReactionFiles(Path reactionsDir, List<FileStorage> reactionFiles)
258259
throws IOException {
259260

260-
List<Path> paths = new ArrayList<>(reactionFiles.size());
261-
262261
for (int i = 0; i < reactionFiles.size(); i++) {
263262
FileStorage rf = reactionFiles.get(i);
264263
String name = safeName(rf.getFilename(), "reactions-" + i + ".reactions");
265264
Path p = reactionsDir.resolve(name);
266265
Files.write(p, nonNullBytes(rf.getData()));
267-
paths.add(p);
268266
}
269267
}
270268
}

app/src/test/java/tools/vitruv/methodologist/vitruvcli/VitruvCliServiceTest.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.nio.file.Path;
1515
import java.util.List;
1616
import java.util.concurrent.TimeUnit;
17+
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
1718
import org.junit.jupiter.api.BeforeEach;
1819
import org.junit.jupiter.api.Test;
1920
import org.mockito.MockedConstruction;
@@ -142,7 +143,9 @@ void run_throwsIllegalState_whenProcessTimesOut() {
142143
.thenReturn(false);
143144
})) {
144145

145-
assertThatThrownBy(() -> service.run(folder, List.of(mm), reactionsDir))
146+
ThrowingCallable runService = () -> service.run(folder, List.of(mm), reactionsDir);
147+
148+
assertThatThrownBy(runService)
146149
.isInstanceOf(IllegalStateException.class)
147150
.hasMessageContaining("timed out");
148151
}
@@ -168,7 +171,9 @@ void run_wrapsIOException_inCLIExecuteException() {
168171
when(pbMock.start()).thenThrow(new IOException("cannot start process"));
169172
})) {
170173

171-
assertThatThrownBy(() -> service.run(folder, List.of(mm), reactionsDir))
174+
ThrowingCallable runnable = () -> service.run(folder, List.of(mm), reactionsDir);
175+
176+
assertThatThrownBy(runnable)
172177
.isInstanceOf(CLIExecuteException.class)
173178
.hasMessageContaining("cannot start process");
174179
}
@@ -198,7 +203,9 @@ void run_wrapsInterruptedException_inCLIExecuteException_andInterruptsThread() {
198203
.thenThrow(new InterruptedException("interrupted"));
199204
})) {
200205

201-
assertThatThrownBy(() -> service.run(folder, List.of(mm), reactionsDir))
206+
ThrowingCallable runnable = () -> service.run(folder, List.of(mm), reactionsDir);
207+
208+
assertThatThrownBy(runnable)
202209
.isInstanceOf(CLIExecuteException.class)
203210
.hasMessageContaining("interrupted");
204211
}

0 commit comments

Comments
 (0)