Skip to content

Commit c80c352

Browse files
committed
Consolidate MoSAPI models and enhance null-safety
- Moves model records into a single MosApiModels.java file. - Switches to ImmutableList/ImmutableMap with non-null defaults in constructors. - Removes redundant pass-through methods in MosApiStateService. - Updates tests to use Java Text Blocks and non-null collection assertions.
1 parent 274289a commit c80c352

21 files changed

+313
-771
lines changed

core/src/main/java/google/registry/mosapi/model/MosApiErrorResponse.java renamed to core/src/main/java/google/registry/mosapi/MosApiErrorResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package google.registry.mosapi.model;
15+
package google.registry.mosapi;
1616

1717
/**
1818
* Represents the generic JSON error response from the MoSAPI service for a 400 Bad Request.

core/src/main/java/google/registry/mosapi/MosApiException.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import static java.lang.annotation.ElementType.TYPE;
1818
import static java.lang.annotation.RetentionPolicy.RUNTIME;
1919

20-
import google.registry.mosapi.model.MosApiErrorResponse;
2120
import java.io.IOException;
2221
import java.lang.annotation.Documented;
2322
import java.lang.annotation.Retention;
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package google.registry.mosapi;
16+
17+
import com.google.common.collect.ImmutableList;
18+
import com.google.common.collect.ImmutableMap;
19+
import com.google.gson.annotations.Expose;
20+
import com.google.gson.annotations.SerializedName;
21+
import java.util.List;
22+
import java.util.Map;
23+
import javax.annotation.Nullable;
24+
25+
/** Data models for ICANN MoSAPI. */
26+
public final class MosApiModels {
27+
28+
private MosApiModels() {}
29+
30+
/**
31+
* A wrapper response containing the state summaries of all monitored services.
32+
*
33+
* <p>This corresponds to the collection of service statuses returned when monitoring the state of
34+
* a TLD
35+
*
36+
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
37+
* Section 5.1</a>
38+
*/
39+
public record AllServicesStateResponse(
40+
// A list of state summaries for each monitored service (e.g. DNS, RDDS, etc.)
41+
@Expose @SerializedName("serviceStates") List<ServiceStateSummary> serviceStates) {
42+
43+
public AllServicesStateResponse {
44+
serviceStates = (serviceStates == null) ? ImmutableList.of() : serviceStates;
45+
}
46+
}
47+
48+
/**
49+
* A summary of a service incident.
50+
*
51+
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
52+
* Section 5.1</a>
53+
*/
54+
public record IncidentSummary(
55+
@Expose @SerializedName("incidentID") String incidentID,
56+
@Expose @SerializedName("startTime") long startTime,
57+
@Expose @SerializedName("falsePositive") boolean falsePositive,
58+
@Expose @SerializedName("state") String state,
59+
@Expose @SerializedName("endTime") @Nullable Long endTime) {}
60+
61+
/**
62+
* A curated summary of the service state for a TLD.
63+
*
64+
* <p>This class aggregates the high-level status of a TLD and details of any active incidents
65+
* affecting specific services (like DNS or RDDS), based on the data structures defined in the
66+
* MoSAPI specification.
67+
*
68+
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
69+
* Section 5.1</a>
70+
*/
71+
public record ServiceStateSummary(
72+
@Expose @SerializedName("tld") String tld,
73+
@Expose @SerializedName("overallStatus") String overallStatus,
74+
@Expose @SerializedName("activeIncidents") List<ServiceStatus> activeIncidents) {
75+
76+
public ServiceStateSummary {
77+
activeIncidents = activeIncidents == null ? ImmutableList.of() : activeIncidents;
78+
}
79+
}
80+
81+
/** Represents the status of a single monitored service. */
82+
public record ServiceStatus(
83+
/**
84+
* A JSON string that contains the status of the Service as seen from the monitoring system.
85+
* Possible values include "Up", "Down", "Disabled", "UP-inconclusive-no-data", etc.
86+
*/
87+
@Expose @SerializedName("status") String status,
88+
89+
// A JSON number that contains the current percentage of the Emergency Threshold
90+
// of the Service. A value of "0" specifies that there are no Incidents
91+
// affecting the threshold.
92+
@Expose @SerializedName("emergencyThreshold") double emergencyThreshold,
93+
@Expose @SerializedName("incidents") List<IncidentSummary> incidents) {
94+
95+
public ServiceStatus {
96+
incidents = incidents == null ? ImmutableList.of() : incidents;
97+
}
98+
}
99+
100+
/**
101+
* Represents the overall health of all monitored services for a TLD.
102+
*
103+
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
104+
* Section 5.1</a>
105+
*/
106+
public record TldServiceState(
107+
@Expose @SerializedName("tld") String tld,
108+
long lastUpdateApiDatabase,
109+
110+
// A JSON string that contains the status of the TLD as seen from the monitoring system
111+
@Expose @SerializedName("status") String status,
112+
113+
// A JSON object containing detailed information for each potential monitored service (i.e.,
114+
// DNS,
115+
// RDDS, EPP, DNSSEC, RDAP).
116+
@Expose @SerializedName("testedServices") Map<String, ServiceStatus> serviceStatuses) {
117+
118+
public TldServiceState {
119+
serviceStatuses = (serviceStatuses == null) ? ImmutableMap.of() : serviceStatuses;
120+
}
121+
}
122+
}

core/src/main/java/google/registry/mosapi/MosApiStateService.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@
2020
import com.google.common.collect.ImmutableSet;
2121
import com.google.common.flogger.FluentLogger;
2222
import google.registry.config.RegistryConfig.Config;
23-
import google.registry.mosapi.model.AllServicesStateResponse;
24-
import google.registry.mosapi.model.ServiceStateSummary;
25-
import google.registry.mosapi.model.ServiceStatus;
26-
import google.registry.mosapi.model.TldServiceState;
23+
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
24+
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
25+
import google.registry.mosapi.MosApiModels.ServiceStatus;
26+
import google.registry.mosapi.MosApiModels.TldServiceState;
2727
import jakarta.inject.Inject;
2828
import jakarta.inject.Named;
29-
import java.util.List;
3029
import java.util.concurrent.CompletableFuture;
3130
import java.util.concurrent.ExecutorService;
3231

@@ -52,14 +51,10 @@ public MosApiStateService(
5251
this.tldExecutor = tldExecutor;
5352
}
5453

55-
/** Shared internal logic to fetch raw data from ICANN MoSAPI state monitoring. */
56-
private TldServiceState fetchRawState(String tld) throws MosApiException {
57-
return serviceMonitoringClient.getTldServiceState(tld);
58-
}
59-
6054
/** Fetches and transforms the service state for a given TLD into a summary. */
6155
public ServiceStateSummary getServiceStateSummary(String tld) throws MosApiException {
62-
return transformToSummary(fetchRawState(tld));
56+
TldServiceState rawState = serviceMonitoringClient.getTldServiceState(tld);
57+
return transformToSummary(rawState);
6358
}
6459

6560
/** Fetches and transforms the service state for all configured TLDs. */
@@ -91,7 +86,7 @@ public AllServicesStateResponse getAllServiceStateSummaries() {
9186
}
9287

9388
private ServiceStateSummary transformToSummary(TldServiceState rawState) {
94-
List<ServiceStatus> activeIncidents = null;
89+
ImmutableList<ServiceStatus> activeIncidents = ImmutableList.of();
9590
if (DOWN_STATUS.equalsIgnoreCase(rawState.status())) {
9691
activeIncidents =
9792
rawState.serviceStatuses().entrySet().stream()

core/src/main/java/google/registry/mosapi/ServiceMonitoringClient.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
import com.google.gson.Gson;
1818
import com.google.gson.JsonIOException;
1919
import com.google.gson.JsonSyntaxException;
20-
import google.registry.mosapi.model.MosApiErrorResponse;
21-
import google.registry.mosapi.model.TldServiceState;
20+
import google.registry.mosapi.MosApiModels.TldServiceState;
2221
import jakarta.inject.Inject;
2322
import java.util.Collections;
2423
import okhttp3.Response;

core/src/main/java/google/registry/mosapi/model/AllServicesStateResponse.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

core/src/main/java/google/registry/mosapi/model/IncidentSummary.java

Lines changed: 0 additions & 32 deletions
This file was deleted.

core/src/main/java/google/registry/mosapi/model/ServiceStateSummary.java

Lines changed: 0 additions & 39 deletions
This file was deleted.

core/src/main/java/google/registry/mosapi/model/ServiceStatus.java

Lines changed: 0 additions & 38 deletions
This file was deleted.

core/src/main/java/google/registry/mosapi/model/TldServiceState.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)