Skip to content

Commit 26b7614

Browse files
committed
Add structured remote-control errors
Introduce structured error responses with codes for remote-control endpoints. Document the error codes in the README.
1 parent e197e6f commit 26b7614

File tree

5 files changed

+131
-3
lines changed

5 files changed

+131
-3
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* fiberoptics-das-producer
4+
* %%
5+
* Copyright (C) 2020 Equinor ASA
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
21+
package com.equinor.fiberoptics.das.remotecontrol;
22+
23+
/**
24+
* Structured error payload for remote-control endpoints.
25+
*/
26+
public record ErrorResponse(String errorCode, String message, String path) {
27+
28+
public static ErrorResponse of(String errorCode, String message, String path) {
29+
return new ErrorResponse(errorCode, message, path);
30+
}
31+
}

das-producer/src/main/java/com/equinor/fiberoptics/das/remotecontrol/RemoteControlController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ public ResponseEntity<?> stop(
8585
RemoteControlService.StopResult result = _remoteControlService.stop(
8686
Optional.ofNullable(acquisitionJson)
8787
);
88-
return result == RemoteControlService.StopResult.NOT_FOUND
89-
? ResponseEntity.notFound().build()
90-
: ResponseEntity.ok().build();
88+
if (result == RemoteControlService.StopResult.NOT_FOUND) {
89+
throw new RemoteControlService.NotFoundException("Acquisition not found.");
90+
}
91+
return ResponseEntity.ok().build();
9192
}
9293

9394
private void verifyApiKey(String apiKey) {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* fiberoptics-das-producer
4+
* %%
5+
* Copyright (C) 2020 Equinor ASA
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
21+
package com.equinor.fiberoptics.das.remotecontrol;
22+
23+
import jakarta.servlet.http.HttpServletRequest;
24+
import org.springframework.http.HttpStatus;
25+
import org.springframework.http.ResponseEntity;
26+
import org.springframework.web.bind.annotation.ExceptionHandler;
27+
import org.springframework.web.bind.annotation.RestControllerAdvice;
28+
29+
/**
30+
* Maps remote-control errors to structured responses.
31+
*/
32+
@RestControllerAdvice(basePackages = "com.equinor.fiberoptics.das.remotecontrol")
33+
public class RemoteControlExceptionHandler {
34+
35+
@ExceptionHandler(RemoteControlService.BadRequestException.class)
36+
public ResponseEntity<ErrorResponse> handleBadRequest(
37+
RemoteControlService.BadRequestException ex,
38+
HttpServletRequest request) {
39+
return build(HttpStatus.BAD_REQUEST, "RC-400", ex.getMessage(), request);
40+
}
41+
42+
@ExceptionHandler(RemoteControlService.UnauthorizedException.class)
43+
public ResponseEntity<ErrorResponse> handleUnauthorized(
44+
RemoteControlService.UnauthorizedException ex,
45+
HttpServletRequest request) {
46+
return build(HttpStatus.UNAUTHORIZED, "RC-401", "Unauthorized", request);
47+
}
48+
49+
@ExceptionHandler(RemoteControlService.NotFoundException.class)
50+
public ResponseEntity<ErrorResponse> handleNotFound(
51+
RemoteControlService.NotFoundException ex,
52+
HttpServletRequest request) {
53+
return build(HttpStatus.NOT_FOUND, "RC-404", ex.getMessage(), request);
54+
}
55+
56+
@ExceptionHandler(IllegalStateException.class)
57+
public ResponseEntity<ErrorResponse> handleIllegalState(
58+
IllegalStateException ex,
59+
HttpServletRequest request) {
60+
return build(HttpStatus.INTERNAL_SERVER_ERROR, "RC-500", ex.getMessage(), request);
61+
}
62+
63+
private ResponseEntity<ErrorResponse> build(
64+
HttpStatus status,
65+
String code,
66+
String message,
67+
HttpServletRequest request) {
68+
String path = request == null ? null : request.getRequestURI();
69+
String safeMessage = message == null || message.isBlank() ? status.getReasonPhrase() : message;
70+
return ResponseEntity.status(status).body(ErrorResponse.of(code, safeMessage, path));
71+
}
72+
}

das-producer/src/main/java/com/equinor/fiberoptics/das/remotecontrol/RemoteControlService.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,4 +444,14 @@ public BadRequestException(String message) {
444444
@ResponseStatus(HttpStatus.UNAUTHORIZED)
445445
public static class UnauthorizedException extends RuntimeException {
446446
}
447+
448+
/**
449+
* Thrown when a requested acquisition does not exist.
450+
*/
451+
@ResponseStatus(HttpStatus.NOT_FOUND)
452+
public static class NotFoundException extends RuntimeException {
453+
public NotFoundException(String message) {
454+
super(message);
455+
}
456+
}
447457
}

readme.adoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,20 @@ Note: You can also send the full profile JSON in the APPLY request body (for con
193193
as long as Custom.das-simulator-profile is present; the simulator will still load the profile
194194
from disk and ignore other fields in the request.
195195

196+
=== Remote-control error responses
197+
198+
Remote-control endpoints return structured error responses when requests are invalid or unauthorized.
199+
200+
.Error codes
201+
|===
202+
|Error code |HTTP status |When it happens
203+
204+
|RC-400|400|Invalid request payload (missing/invalid JSON or required fields).
205+
|RC-401|401|Missing or invalid X-Api-Key.
206+
|RC-404|404|Requested acquisition id not found when stopping.
207+
|RC-500|500|Unexpected internal error during remote-control handling.
208+
|===
209+
196210
Details for ProdML can be found here: http://w3.energistics.org/energyML/data/prodml/v2.0/doc/prodml_schema_overview.html
197211

198212
== Building and running

0 commit comments

Comments
 (0)