diff --git a/.github/workflows/fabricv4_test_runner.yml b/.github/workflows/fabricv4_test_runner.yml index 6d1c7d3a..e47fc8c6 100644 --- a/.github/workflows/fabricv4_test_runner.yml +++ b/.github/workflows/fabricv4_test_runner.yml @@ -6,15 +6,20 @@ on: types: - completed workflow_dispatch: + pull_request: + types: [labeled] jobs: build: runs-on: ubuntu-latest - if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} + if: >- + ${{ github.event_name == 'workflow_dispatch' + || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') + || (github.event_name == 'pull_request' && github.event.label.name == 'run-fabric-tests') }} steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.workflow_run.head_branch || github.ref }} + ref: ${{ github.event.pull_request.head.sha || github.event.workflow_run.head_branch || github.ref }} - name: Set up JDK 11 uses: actions/setup-java@v4 @@ -54,6 +59,8 @@ jobs: jdk: 21 - class: ServiceProfilesApiTest jdk: 21 + - class: InternetAccessApiTest + jdk: 21 env: TEST_HOST_URL: ${{ secrets.TEST_HOST_URL }} @@ -62,7 +69,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.workflow_run.head_branch || github.ref }} + ref: ${{ github.event.pull_request.head.sha || github.event.workflow_run.head_branch || github.ref }} - name: Set up JDK ${{ matrix.testConfig.jdk }} uses: actions/setup-java@v4 @@ -136,7 +143,7 @@ jobs: notify-slack: needs: test - if: always() + if: always() && needs.test.result != 'skipped' runs-on: ubuntu-latest outputs: diff --git a/README.md b/README.md index 49984c8d..21fb1f33 100644 --- a/README.md +++ b/README.md @@ -60,3 +60,77 @@ public class Example { } } ``` + +## Equinix Internet Access (EIA) + +The Fabric v4 module supports **Equinix Internet Access (EIA)** services. The generated +clients live under `com.equinix.sdk.fabricv4` (`api` for clients, `model` for data classes). + +Two API clients cover the EIA workflow: + +- **`InternetAccessServicesApi`** — manage EIA services: create, get, search, + patch (e.g. update bandwidth) and delete. +- **`IpBlocksApi`** — manage the IP blocks an EIA service routes: submit, search, + get, patch and delete. + +Supported routing protocols: `DIRECT`, `STATIC`, and `BGP` +(`InternetAccessRoutingProtocolType`). Service state is reported via +`InternetAccessServiceState` (`PROVISIONING`, `PROVISIONED`, `FAILED`, +`DEPROVISIONING`, `DEPROVISIONED`). + +### Example: create an EIA service + +```java +import com.equinix.sdk.fabricv4.ApiClient; +import com.equinix.sdk.fabricv4.ApiException; +import com.equinix.sdk.fabricv4.Configuration; +import com.equinix.sdk.fabricv4.auth.HttpBearerAuth; +import com.equinix.sdk.fabricv4.api.InternetAccessServicesApi; +import com.equinix.sdk.fabricv4.model.*; +import java.util.UUID; + +import static java.util.Collections.singletonList; + +public class EiaExample { + public static void main(String[] args) throws ApiException { + ApiClient client = Configuration.getDefaultApiClient(); + client.setBasePath("https://api.equinix.com"); + ((HttpBearerAuth) client.getAuthentication("BearerAuth")) + .setBearerToken(""); + + InternetAccessServicesApi eiaApi = new InternetAccessServicesApi(client); + + // DIRECT routing: reference an existing IA_VC connection and a customer IPv4 block, + // and supply the Equinix peer IP from that block. + InternetAccessRoutingProtocolDirectRequest routing = + new InternetAccessRoutingProtocolDirectRequest() + .addConnectionsItem(new InternetAccessConnectionDirectRequest() + .uuid(UUID.fromString("")) + .peeringIpv4(new InternetAccessPeeringIpv4Request().equinixPeerIp("67.223.23.5"))); + routing.type(InternetAccessRoutingProtocolType.DIRECT); + routing.addCustomerRoutesItem(new InternetAccessCustomerRouteRequest() + .ipBlock(new InternetAccessIpBlockRequest().uuid(UUID.fromString("")))); + + InternetAccessPostRequest request = new InternetAccessPostRequest() + .type(InternetAccessServiceType.SINGLE_IA) + .name("my-eia-service") + .bandwidth(50) + .routingProtocol(routing) + .billing(new InternetAccessPostRequestBilling().type(InternetAccessBillingType.FIXED)) + .project(new Project().projectId("")) + .account(new InternetAccessAccount().accountNumber("")); + + InternetAccessService service = eiaApi.createEiaService(request); + System.out.println("Created EIA service: " + service.getUuid() + " state=" + service.getState()); + + // Update bandwidth + eiaApi.patchEiaService(service.getUuid(), singletonList(new InternetAccessPatchOperationUpdate() + .op(InternetAccessPatchOperationUpdateAllowedOp.REPLACE) + .path("/bandwidth") + .value(100))); + + // Delete when no longer needed + eiaApi.deleteEiaService(service.getUuid()); + } +} +``` diff --git a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/InternetAccessApiTest.java b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/InternetAccessApiTest.java new file mode 100644 index 00000000..cd3d0eda --- /dev/null +++ b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/InternetAccessApiTest.java @@ -0,0 +1,337 @@ +package com.equinix.openapi.fabric.tests; + +import com.equinix.openapi.fabric.tests.dto.users.UsersItem; +import com.equinix.openapi.fabric.tests.helpers.Utils; +import com.equinix.sdk.fabricv4.ApiException; +import com.equinix.sdk.fabricv4.model.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static com.equinix.openapi.fabric.tests.ConnectionsApiTest.waitForConnectionIsInState; +import static com.equinix.openapi.fabric.tests.PortsApiTest.getPorts; +import static com.equinix.openapi.fabric.tests.helpers.Apis.*; +import static com.equinix.openapi.fabric.tests.helpers.TokenGenerator.users; +import static com.equinix.openapi.fabric.tests.helpers.Utils.getRandomVlanNumber; +import static java.util.Collections.singletonList; +import static org.junit.Assert.*; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class InternetAccessApiTest { + + private static final UsersItem.UserName userName = UsersItem.UserName.PANTHERS_FNV; + private static final UsersItem testData = Utils.getUserData(userName); + private static final String IA_METRO = "SV"; + private static final int DELETE_RETRY_INTERVAL_MS = 10000; + private static final int DELETE_MAX_ATTEMPTS = 11; + private static final int STATE_RETRY_INTERVAL_MS = 10000; + private static final int STATE_MAX_ATTEMPTS = 20; + private static final int INITIAL_BANDWIDTH = 50; + private static final int[] BANDWIDTH_CANDIDATES = {100, 200, 500, 1000}; + private static UUID createdServiceUuid; + private static UUID createdIpBlockUuid; + + @BeforeClass + public static void setUp() { + setUserName(userName); + } + + @AfterClass + public static void tearDown() { + boolean serviceDeleted = waitForServiceDeleted(); + deleteCreatedIpBlock(); + assertTrue("Internet Access Service " + createdServiceUuid + " was not deleted", serviceDeleted); + } + + @Test + public void test1_createEiaService() throws ApiException { + InternetAccessService service = createInternetAccessService(); + createdServiceUuid = service.getUuid(); + assertNotNull("Created Internet Access Service has no UUID", createdServiceUuid); + } + + @Test + public void test2_getEiaService() throws ApiException { + assertNotNull("No Internet Access Service was created", createdServiceUuid); + InternetAccessService service = internetAccessServicesApi.getEiaService(createdServiceUuid); + assertEquals(200, internetAccessServicesApi.getApiClient().getStatusCode()); + assertEquals(createdServiceUuid, service.getUuid()); + } + + @Test + public void test3_searchEiaServices() throws ApiException { + assertNotNull("No Internet Access Service was created", createdServiceUuid); + InternetAccessServices services = searchServices(); + assertEquals(200, internetAccessServicesApi.getApiClient().getStatusCode()); + assertFalse(services.getData().isEmpty()); + assertTrue("Search returned services that are not PROVISIONED", services.getData().stream() + .allMatch(s -> s.getState() == InternetAccessServiceState.PROVISIONED)); + boolean found = services.getData().stream() + .anyMatch(s -> createdServiceUuid.equals(s.getUuid())); + assertTrue("Created Internet Access Service " + createdServiceUuid + " not found in search results", found); + } + + @Test + public void test4_patchEiaService() throws ApiException { + assertNotNull("No Internet Access Service was created", createdServiceUuid); + + for (int bandwidth : BANDWIDTH_CANDIDATES) { + try { + InternetAccessPatchOperationUpdate operation = new InternetAccessPatchOperationUpdate() + .op(InternetAccessPatchOperationUpdateAllowedOp.REPLACE) + .path("/bandwidth") + .value(bandwidth); + + internetAccessServicesApi.patchEiaService(createdServiceUuid, singletonList(operation)); + assertEquals(202, internetAccessServicesApi.getApiClient().getStatusCode()); + return; + } catch (ApiException e) { + String body = String.valueOf(e.getResponseBody()); + if (body.contains("EQ-7100076")) { + continue; + } + if (body.contains("EQ-7100077")) { + try { + Thread.sleep(STATE_RETRY_INTERVAL_MS); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + continue; + } + throw e; + } + } + fail("Could not patch bandwidth to a new value for service " + createdServiceUuid); + } + + @Test + public void test5_deleteEiaService() throws ApiException { + assertNotNull("No Internet Access Service was created", createdServiceUuid); + assertTrue("Internet Access Service was not PROVISIONED before delete", + waitForServiceIsInState(createdServiceUuid, InternetAccessServiceState.PROVISIONED)); + assertTrue("Internet Access Service was not deleted in time", deleteEiaService(createdServiceUuid)); + } + + private static boolean waitForServiceDeleted() { + if (createdServiceUuid == null) { + return true; + } + for (int attempt = 1; attempt <= DELETE_MAX_ATTEMPTS; attempt++) { + try { + InternetAccessServiceState state = internetAccessServicesApi.getEiaService(createdServiceUuid).getState(); + if (state == InternetAccessServiceState.DEPROVISIONED) { + return true; + } + } catch (ApiException e) { + if (e.getCode() == 404) { + return true; + } + System.out.println("Service delete check attempt " + attempt + " for " + createdServiceUuid + ": " + e.getMessage()); + } + try { + Thread.sleep(DELETE_RETRY_INTERVAL_MS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + System.out.println("Internet Access Service " + createdServiceUuid + " was not deprovisioned within the timeout"); + return false; + } + + private static void deleteCreatedIpBlock() { + if (createdIpBlockUuid == null) { + return; + } + for (int attempt = 1; attempt <= DELETE_MAX_ATTEMPTS; attempt++) { + try { + ipBlocksApi.deleteIpBlockById(createdIpBlockUuid); + if (ipBlocksApi.getApiClient().getStatusCode() / 100 == 2) { + return; + } + } catch (ApiException e) { + System.out.println("Ip block delete attempt " + attempt + " for " + createdIpBlockUuid + " not ready: " + e.getMessage()); + } + try { + Thread.sleep(DELETE_RETRY_INTERVAL_MS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + System.out.println("Ip block " + createdIpBlockUuid + " could not be deleted within the timeout"); + } + + private static InternetAccessServices searchServices() throws ApiException { + InternetAccessSearchRequest requestBody = new InternetAccessSearchRequest().filter( + new SearchExpression() + .addAndItem(new SearchExpression() + .property("/project/projectId") + .operator(SearchExpression.OperatorEnum.EQUAL) + .values(singletonList(testData.getProjectId()))) + .addAndItem(new SearchExpression() + .property("/state") + .operator(SearchExpression.OperatorEnum.EQUAL) + .values(singletonList(InternetAccessServiceState.PROVISIONED.getValue())))) + .pagination(new PaginationRequest().offset(0).limit(100)); + + return internetAccessServicesApi.searchEiaServices(requestBody); + } + + private static boolean waitForServiceIsInState(UUID uuid, InternetAccessServiceState expectedState) throws ApiException { + InternetAccessServiceState currentState = null; + for (int attempt = 1; attempt <= STATE_MAX_ATTEMPTS; attempt++) { + currentState = internetAccessServicesApi.getEiaService(uuid).getState(); + if (currentState == expectedState) { + return true; + } + if (currentState == InternetAccessServiceState.FAILED) { + fail("Internet Access Service " + uuid + " reached FAILED state"); + } + try { + Thread.sleep(STATE_RETRY_INTERVAL_MS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + System.out.println("Internet Access Service " + uuid + " did not reach " + expectedState + + " state (current: " + currentState + ")"); + return false; + } + + private static UUID createIaConnection() throws ApiException { + Port port = selectDot1qPort(); + + ConnectionPostRequest connectionPostRequest = new ConnectionPostRequest() + .name("panthers-eia-con-" + getRandomVlanNumber()) + .type(ConnectionType.IA_VC).bandwidth(INITIAL_BANDWIDTH) + .project(new Project().projectId(testData.getProjectId())) + .notifications(singletonList(new SimplifiedNotification().type(SimplifiedNotification.TypeEnum.ALL) + .emails(singletonList("panthers_auto@equinix.com")))) + .zSide(new ConnectionSide() + .accessPoint(new AccessPoint().type(AccessPointType.SP) + .profile(new SimplifiedServiceProfile() + .type(ServiceProfileTypeEnum.IA_PROFILE) + .uuid(UUID.fromString(testData.getIaProfileUuid()))) + .location(new SimplifiedLocation() + .metroCode(IA_METRO)))); + + Connection connection = null; + for (int i = 0; i < 3; i++) { + connectionPostRequest.aSide(new ConnectionSide() + .accessPoint(new AccessPoint() + .type(AccessPointType.COLO) + .port(new SimplifiedPort() + .uuid(port.getUuid())) + .linkProtocol(new SimplifiedLinkProtocol() + .type(LinkProtocolType.DOT1Q) + .vlanTag(getRandomVlanNumber())))); + + connection = connectionsApi.createConnection(connectionPostRequest, false); + if (connectionsApi.getApiClient().getStatusCode() == 201) { + break; + } + } + + assertEquals(201, connectionsApi.getApiClient().getStatusCode()); + users.get(userName).getUserResources().addConnectionUuid(connection.getUuid()); + waitForConnectionIsInState(connection.getUuid(), EquinixStatus.PROVISIONED); + return UUID.fromString(connection.getUuid()); + } + + private static Port selectDot1qPort() throws ApiException { + List ports = getPorts(userName).getData().stream() + .filter(p -> p.getLocation() != null && IA_METRO.equals( + p.getLocation().getMetroCode())) + .filter(p -> p.getEncapsulation() != null && p.getEncapsulation().getType() == PortEncapsulation.TypeEnum.DOT1Q) + .collect(Collectors.toList()); + + assertFalse("No DOT1Q port available in metro " + IA_METRO, ports.isEmpty()); + return ports.get(0); + } + + // For a DIRECT routing protocol the connection must carry the Equinix peering IP, which is a + // host of a customer-owned IPv4 block referenced in customerRoutes. Always create a fresh + // /24 block (mirrors the portal flow captured in test3.har); it is removed in @AfterClass. + private static IpBlock createCustomerIpv4Block() throws ApiException { + String prefix = "67.223." + (1 + Math.floorMod(getRandomVlanNumber(), 254)) + ".0/24"; + SubmitIpBlockRequestBody requestBody = new SubmitIpBlockRequestBody() + .type(TypeOfIpBlockProduct.IPV4_IP_BLOCK) + .prefix(prefix) + .project(new IpBlockProjectRequest().projectId(testData.getProjectId())); + + IpBlock ipBlock = ipBlocksApi.submitIpBlock(requestBody); + assertEquals(202, ipBlocksApi.getApiClient().getStatusCode()); + createdIpBlockUuid = ipBlock.getUuid(); + return ipBlock; + } + + // Equinix peering IP = the 6th host of the customer block (e.g. 67.223.23.0/24 -> 67.223.23.5), + // matching the portal request in test3.har. + private static String equinixPeerIpFor(IpBlock ipBlock) { + String[] octets = ipBlock.getPrefix().split("/")[0].split("\\."); + return octets[0] + "." + octets[1] + "." + octets[2] + ".5"; + } + + private static boolean deleteEiaService(UUID uuid) { + for (int attempt = 1; attempt <= DELETE_MAX_ATTEMPTS; attempt++) { + try { + InternetAccessServiceState state = internetAccessServicesApi.getEiaService(uuid).getState(); + if (state == InternetAccessServiceState.DEPROVISIONED || state == InternetAccessServiceState.DEPROVISIONING) { + return true; + } + internetAccessServicesApi.deleteEiaService(uuid); + if (internetAccessServicesApi.getApiClient().getStatusCode() / 100 == 2) { + return true; + } + } catch (ApiException e) { + System.out.println("Delete attempt " + attempt + " for " + uuid + " not ready: " + e.getMessage()); + } + try { + Thread.sleep(DELETE_RETRY_INTERVAL_MS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + System.out.println("Internet Access Service " + uuid + " could not be deleted within the timeout"); + return false; + } + + private InternetAccessService createInternetAccessService() throws ApiException { + UUID connectionUuid = createIaConnection(); + IpBlock ipBlock = createCustomerIpv4Block(); + String equinixPeerIp = equinixPeerIpFor(ipBlock); + + InternetAccessRoutingProtocolDirectRequest routingProtocol = new InternetAccessRoutingProtocolDirectRequest() + .addConnectionsItem(new InternetAccessConnectionDirectRequest() + .uuid(connectionUuid) + .peeringIpv4(new InternetAccessPeeringIpv4Request().equinixPeerIp(equinixPeerIp))); + routingProtocol.type(InternetAccessRoutingProtocolType.DIRECT); + routingProtocol.addCustomerRoutesItem(new InternetAccessCustomerRouteRequest() + .ipBlock(new InternetAccessIpBlockRequest() + .uuid(ipBlock.getUuid()))); + + InternetAccessPostRequest requestBody = new InternetAccessPostRequest() + .type(InternetAccessServiceType.SINGLE_IA) + .name("panthers_eia_" + getRandomVlanNumber()) + .bandwidth(INITIAL_BANDWIDTH) + .routingProtocol(routingProtocol) + .billing(new InternetAccessPostRequestBilling() + .type(InternetAccessBillingType.FIXED)) + .project(new Project().projectId(testData.getProjectId())) + .account(new InternetAccessAccount() + .accountNumber(testData.getAccountNumberEIA())); + + InternetAccessService service = internetAccessServicesApi.createEiaService(requestBody); + users.get(userName).getUserResources().addInternetAccessServiceUuid(service.getUuid()); + assertEquals(201, internetAccessServicesApi.getApiClient().getStatusCode()); + + assertTrue("Internet Access Service did not reach PROVISIONED state", + waitForServiceIsInState(service.getUuid(), InternetAccessServiceState.PROVISIONED)); + return service; + } +} diff --git a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UserResources.java b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UserResources.java index 9078e600..bae0169f 100644 --- a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UserResources.java +++ b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UserResources.java @@ -10,6 +10,7 @@ public class UserResources { private final List routingProtocolsUuid = new ArrayList<>(); private final List networksUuid = new ArrayList<>(); private final List serviceProfilesUuid = new ArrayList<>(); + private final List internetAccessServicesUuid = new ArrayList<>(); public List getCloudRoutersUuid() { return cloudRoutersUuid; @@ -52,6 +53,14 @@ public void addServiceProfileUuid(UUID serviceProfilesUuid) { this.serviceProfilesUuid.add(serviceProfilesUuid); } + public List getInternetAccessServicesUuid() { + return internetAccessServicesUuid; + } + + public void addInternetAccessServiceUuid(UUID internetAccessServiceUuid) { + this.internetAccessServicesUuid.add(internetAccessServiceUuid); + } + public class RoutingProtocolDto { private UUID routingInstanceUuid; private UUID connectionUuid; diff --git a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UsersItem.java b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UsersItem.java index 0a90439e..b0961db1 100644 --- a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UsersItem.java +++ b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/dto/users/UsersItem.java @@ -1,8 +1,8 @@ package com.equinix.openapi.fabric.tests.dto.users; -import com.fasterxml.jackson.annotation.JsonProperty; import com.equinix.openapi.fabric.tests.dto.port.PortDto; import com.equinix.openapi.fabric.tests.dto.port.VirtualDevicesItem; +import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; @@ -29,6 +29,12 @@ public class UsersItem { @JsonProperty("client_id") private String clientId; + @JsonProperty("accountNumberEIA") + private String accountNumberEIA; + + @JsonProperty("iaProfileUuid") + private String iaProfileUuid; + public List getPorts() { return ports; } @@ -85,6 +91,22 @@ public void setClientId(String clientId) { this.clientId = clientId; } + public String getAccountNumberEIA() { + return accountNumberEIA; + } + + public void setAccountNumberEIA(String accountNumberEIA) { + this.accountNumberEIA = accountNumberEIA; + } + + public String getIaProfileUuid() { + return iaProfileUuid; + } + + public void setIaProfileUuid(String iaProfileUuid) { + this.iaProfileUuid = iaProfileUuid; + } + public enum UserName { PANTHERS_FCR("fcr"), PANTHERS_FNV("fnv"); diff --git a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/helpers/Apis.java b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/helpers/Apis.java index 92163323..cc5f9b7a 100644 --- a/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/helpers/Apis.java +++ b/equinix-openapi-fabric-tests/src/test/java/com/equinix/openapi/fabric/tests/helpers/Apis.java @@ -21,6 +21,7 @@ public class Apis { public static ServiceTokensApi serviceTokensApi; public static StatisticsApi statisticsApi; public static InternetAccessServicesApi internetAccessServicesApi; + public static IpBlocksApi ipBlocksApi; private static UsersItem.UserName currentUser; static { @@ -54,5 +55,6 @@ private static void setApis() { serviceTokensApi = new ServiceTokensApi(TokenGenerator.getApiClient(currentUser)); statisticsApi = new StatisticsApi(TokenGenerator.getApiClient(currentUser)); internetAccessServicesApi = new InternetAccessServicesApi(TokenGenerator.getApiClient(currentUser)); + ipBlocksApi = new IpBlocksApi(TokenGenerator.getApiClient(currentUser)); } } diff --git a/services/fabricv4/docs/InternetAccessService.md b/services/fabricv4/docs/InternetAccessService.md index 4e42039f..b9687d9a 100644 --- a/services/fabricv4/docs/InternetAccessService.md +++ b/services/fabricv4/docs/InternetAccessService.md @@ -20,7 +20,7 @@ |**billing** | [**InternetAccessBilling**](InternetAccessBilling.md) | | | |**account** | [**InternetAccessAccount**](InternetAccessAccount.md) | | | |**project** | [**Project**](Project.md) | | | -|**order** | [**InternetAccessOrder**](InternetAccessOrder.md) | | | +|**order** | [**InternetAccessOrder**](InternetAccessOrder.md) | | [optional] | |**changeLog** | [**Changelog**](Changelog.md) | | | |**useCase** | **InternetAccessUseCase** | | | diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgp.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgp.java index 7a270200..4d597a91 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgp.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgp.java @@ -156,50 +156,6 @@ public void setCustomerAsnRange(@javax.annotation.Nonnull InternetAccessCustomer this.customerAsnRange = customerAsnRange; } - /** - * A container for additional, undeclared properties. - * This is a holder for any undeclared properties as specified with - * the 'additionalProperties' keyword in the OAS document. - */ - private Map additionalProperties; - - /** - * Set the additional (undeclared) property with the specified name and value. - * If the property does not already exist, create it otherwise replace it. - * - * @param key name of the property - * @param value value of the property - * @return the InternetAccessRoutingProtocolBgp instance itself - */ - public InternetAccessRoutingProtocolBgp putAdditionalProperty(String key, Object value) { - if (this.additionalProperties == null) { - this.additionalProperties = new HashMap(); - } - this.additionalProperties.put(key, value); - return this; - } - - /** - * Return the additional (undeclared) property. - * - * @return a map of objects - */ - public Map getAdditionalProperties() { - return additionalProperties; - } - - /** - * Return the additional (undeclared) property with the specified name. - * - * @param key name of the property - * @return an object - */ - public Object getAdditionalProperty(String key) { - if (this.additionalProperties == null) { - return null; - } - return this.additionalProperties.get(key); - } @Override @@ -214,14 +170,13 @@ public boolean equals(Object o) { return Objects.equals(this.exportPolicy, internetAccessRoutingProtocolBgp.exportPolicy) && Objects.equals(this.customerAsn, internetAccessRoutingProtocolBgp.customerAsn) && Objects.equals(this.bgpAuthKey, internetAccessRoutingProtocolBgp.bgpAuthKey) && - Objects.equals(this.customerAsnRange, internetAccessRoutingProtocolBgp.customerAsnRange)&& - Objects.equals(this.additionalProperties, internetAccessRoutingProtocolBgp.additionalProperties) && + Objects.equals(this.customerAsnRange, internetAccessRoutingProtocolBgp.customerAsnRange) && super.equals(o); } @Override public int hashCode() { - return Objects.hash(exportPolicy, customerAsn, bgpAuthKey, customerAsnRange, super.hashCode(), additionalProperties); + return Objects.hash(exportPolicy, customerAsn, bgpAuthKey, customerAsnRange, super.hashCode()); } @Override @@ -233,7 +188,6 @@ public String toString() { sb.append(" customerAsn: ").append(toIndentedString(customerAsn)).append("\n"); sb.append(" bgpAuthKey: ").append(toIndentedString(bgpAuthKey)).append("\n"); sb.append(" customerAsnRange: ").append(toIndentedString(customerAsnRange)).append("\n"); - sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgpRequest.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgpRequest.java index ba9c7359..d33fdbb5 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgpRequest.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolBgpRequest.java @@ -188,50 +188,6 @@ public void setCustomerAsnRange(@javax.annotation.Nullable InternetAccessCustome this.customerAsnRange = customerAsnRange; } - /** - * A container for additional, undeclared properties. - * This is a holder for any undeclared properties as specified with - * the 'additionalProperties' keyword in the OAS document. - */ - private Map additionalProperties; - - /** - * Set the additional (undeclared) property with the specified name and value. - * If the property does not already exist, create it otherwise replace it. - * - * @param key name of the property - * @param value value of the property - * @return the InternetAccessRoutingProtocolBgpRequest instance itself - */ - public InternetAccessRoutingProtocolBgpRequest putAdditionalProperty(String key, Object value) { - if (this.additionalProperties == null) { - this.additionalProperties = new HashMap(); - } - this.additionalProperties.put(key, value); - return this; - } - - /** - * Return the additional (undeclared) property. - * - * @return a map of objects - */ - public Map getAdditionalProperties() { - return additionalProperties; - } - - /** - * Return the additional (undeclared) property with the specified name. - * - * @param key name of the property - * @return an object - */ - public Object getAdditionalProperty(String key) { - if (this.additionalProperties == null) { - return null; - } - return this.additionalProperties.get(key); - } @Override @@ -247,14 +203,13 @@ public boolean equals(Object o) { Objects.equals(this.exportPolicy, internetAccessRoutingProtocolBgpRequest.exportPolicy) && Objects.equals(this.customerAsn, internetAccessRoutingProtocolBgpRequest.customerAsn) && Objects.equals(this.bgpAuthKey, internetAccessRoutingProtocolBgpRequest.bgpAuthKey) && - Objects.equals(this.customerAsnRange, internetAccessRoutingProtocolBgpRequest.customerAsnRange)&& - Objects.equals(this.additionalProperties, internetAccessRoutingProtocolBgpRequest.additionalProperties) && + Objects.equals(this.customerAsnRange, internetAccessRoutingProtocolBgpRequest.customerAsnRange) && super.equals(o); } @Override public int hashCode() { - return Objects.hash(connections, exportPolicy, customerAsn, bgpAuthKey, customerAsnRange, super.hashCode(), additionalProperties); + return Objects.hash(connections, exportPolicy, customerAsn, bgpAuthKey, customerAsnRange, super.hashCode()); } @Override @@ -267,7 +222,6 @@ public String toString() { sb.append(" customerAsn: ").append(toIndentedString(customerAsn)).append("\n"); sb.append(" bgpAuthKey: ").append(toIndentedString(bgpAuthKey)).append("\n"); sb.append(" customerAsnRange: ").append(toIndentedString(customerAsnRange)).append("\n"); - sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirect.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirect.java index 4073d71c..7bcc2dc3 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirect.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirect.java @@ -58,50 +58,6 @@ public class InternetAccessRoutingProtocolDirect extends InternetAccessRoutingProtocol { public InternetAccessRoutingProtocolDirect() { } - /** - * A container for additional, undeclared properties. - * This is a holder for any undeclared properties as specified with - * the 'additionalProperties' keyword in the OAS document. - */ - private Map additionalProperties; - - /** - * Set the additional (undeclared) property with the specified name and value. - * If the property does not already exist, create it otherwise replace it. - * - * @param key name of the property - * @param value value of the property - * @return the InternetAccessRoutingProtocolDirect instance itself - */ - public InternetAccessRoutingProtocolDirect putAdditionalProperty(String key, Object value) { - if (this.additionalProperties == null) { - this.additionalProperties = new HashMap(); - } - this.additionalProperties.put(key, value); - return this; - } - - /** - * Return the additional (undeclared) property. - * - * @return a map of objects - */ - public Map getAdditionalProperties() { - return additionalProperties; - } - - /** - * Return the additional (undeclared) property with the specified name. - * - * @param key name of the property - * @return an object - */ - public Object getAdditionalProperty(String key) { - if (this.additionalProperties == null) { - return null; - } - return this.additionalProperties.get(key); - } @Override @@ -117,7 +73,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), additionalProperties); + return Objects.hash(super.hashCode()); } @Override @@ -125,7 +81,6 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class InternetAccessRoutingProtocolDirect {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); - sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirectRequest.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirectRequest.java index 9e20b470..e85f788e 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirectRequest.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolDirectRequest.java @@ -90,50 +90,6 @@ public void setConnections(@javax.annotation.Nonnull List additionalProperties; - - /** - * Set the additional (undeclared) property with the specified name and value. - * If the property does not already exist, create it otherwise replace it. - * - * @param key name of the property - * @param value value of the property - * @return the InternetAccessRoutingProtocolDirectRequest instance itself - */ - public InternetAccessRoutingProtocolDirectRequest putAdditionalProperty(String key, Object value) { - if (this.additionalProperties == null) { - this.additionalProperties = new HashMap(); - } - this.additionalProperties.put(key, value); - return this; - } - - /** - * Return the additional (undeclared) property. - * - * @return a map of objects - */ - public Map getAdditionalProperties() { - return additionalProperties; - } - - /** - * Return the additional (undeclared) property with the specified name. - * - * @param key name of the property - * @return an object - */ - public Object getAdditionalProperty(String key) { - if (this.additionalProperties == null) { - return null; - } - return this.additionalProperties.get(key); - } @Override @@ -145,14 +101,13 @@ public boolean equals(Object o) { return false; } InternetAccessRoutingProtocolDirectRequest internetAccessRoutingProtocolDirectRequest = (InternetAccessRoutingProtocolDirectRequest) o; - return Objects.equals(this.connections, internetAccessRoutingProtocolDirectRequest.connections)&& - Objects.equals(this.additionalProperties, internetAccessRoutingProtocolDirectRequest.additionalProperties) && + return Objects.equals(this.connections, internetAccessRoutingProtocolDirectRequest.connections) && super.equals(o); } @Override public int hashCode() { - return Objects.hash(connections, super.hashCode(), additionalProperties); + return Objects.hash(connections, super.hashCode()); } @Override @@ -161,7 +116,6 @@ public String toString() { sb.append("class InternetAccessRoutingProtocolDirectRequest {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); sb.append(" connections: ").append(toIndentedString(connections)).append("\n"); - sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStatic.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStatic.java index 3578f67a..4bc72c89 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStatic.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStatic.java @@ -58,50 +58,6 @@ public class InternetAccessRoutingProtocolStatic extends InternetAccessRoutingProtocol { public InternetAccessRoutingProtocolStatic() { } - /** - * A container for additional, undeclared properties. - * This is a holder for any undeclared properties as specified with - * the 'additionalProperties' keyword in the OAS document. - */ - private Map additionalProperties; - - /** - * Set the additional (undeclared) property with the specified name and value. - * If the property does not already exist, create it otherwise replace it. - * - * @param key name of the property - * @param value value of the property - * @return the InternetAccessRoutingProtocolStatic instance itself - */ - public InternetAccessRoutingProtocolStatic putAdditionalProperty(String key, Object value) { - if (this.additionalProperties == null) { - this.additionalProperties = new HashMap(); - } - this.additionalProperties.put(key, value); - return this; - } - - /** - * Return the additional (undeclared) property. - * - * @return a map of objects - */ - public Map getAdditionalProperties() { - return additionalProperties; - } - - /** - * Return the additional (undeclared) property with the specified name. - * - * @param key name of the property - * @return an object - */ - public Object getAdditionalProperty(String key) { - if (this.additionalProperties == null) { - return null; - } - return this.additionalProperties.get(key); - } @Override @@ -117,7 +73,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), additionalProperties); + return Objects.hash(super.hashCode()); } @Override @@ -125,7 +81,6 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class InternetAccessRoutingProtocolStatic {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); - sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStaticRequest.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStaticRequest.java index 4797daf3..bf1043cf 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStaticRequest.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessRoutingProtocolStaticRequest.java @@ -90,50 +90,6 @@ public void setConnections(@javax.annotation.Nonnull List additionalProperties; - - /** - * Set the additional (undeclared) property with the specified name and value. - * If the property does not already exist, create it otherwise replace it. - * - * @param key name of the property - * @param value value of the property - * @return the InternetAccessRoutingProtocolStaticRequest instance itself - */ - public InternetAccessRoutingProtocolStaticRequest putAdditionalProperty(String key, Object value) { - if (this.additionalProperties == null) { - this.additionalProperties = new HashMap(); - } - this.additionalProperties.put(key, value); - return this; - } - - /** - * Return the additional (undeclared) property. - * - * @return a map of objects - */ - public Map getAdditionalProperties() { - return additionalProperties; - } - - /** - * Return the additional (undeclared) property with the specified name. - * - * @param key name of the property - * @return an object - */ - public Object getAdditionalProperty(String key) { - if (this.additionalProperties == null) { - return null; - } - return this.additionalProperties.get(key); - } @Override @@ -145,14 +101,13 @@ public boolean equals(Object o) { return false; } InternetAccessRoutingProtocolStaticRequest internetAccessRoutingProtocolStaticRequest = (InternetAccessRoutingProtocolStaticRequest) o; - return Objects.equals(this.connections, internetAccessRoutingProtocolStaticRequest.connections)&& - Objects.equals(this.additionalProperties, internetAccessRoutingProtocolStaticRequest.additionalProperties) && + return Objects.equals(this.connections, internetAccessRoutingProtocolStaticRequest.connections) && super.equals(o); } @Override public int hashCode() { - return Objects.hash(connections, super.hashCode(), additionalProperties); + return Objects.hash(connections, super.hashCode()); } @Override @@ -161,7 +116,6 @@ public String toString() { sb.append("class InternetAccessRoutingProtocolStaticRequest {\n"); sb.append(" ").append(toIndentedString(super.toString())).append("\n"); sb.append(" connections: ").append(toIndentedString(connections)).append("\n"); - sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessService.java b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessService.java index a6b3414b..dd86891e 100644 --- a/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessService.java +++ b/services/fabricv4/src/main/java/com/equinix/sdk/fabricv4/model/InternetAccessService.java @@ -132,7 +132,7 @@ public class InternetAccessService { public static final String SERIALIZED_NAME_ORDER = "order"; @SerializedName(SERIALIZED_NAME_ORDER) - @javax.annotation.Nonnull + @javax.annotation.Nullable private InternetAccessOrder order; public static final String SERIALIZED_NAME_CHANGE_LOG = "changeLog"; @@ -403,7 +403,7 @@ public void setProject(@javax.annotation.Nonnull Project project) { } - public InternetAccessService order(@javax.annotation.Nonnull InternetAccessOrder order) { + public InternetAccessService order(@javax.annotation.Nullable InternetAccessOrder order) { this.order = order; return this; } @@ -412,12 +412,12 @@ public InternetAccessService order(@javax.annotation.Nonnull InternetAccessOrder * Get order * @return order */ - @javax.annotation.Nonnull + @javax.annotation.Nullable public InternetAccessOrder getOrder() { return order; } - public void setOrder(@javax.annotation.Nonnull InternetAccessOrder order) { + public void setOrder(@javax.annotation.Nullable InternetAccessOrder order) { this.order = order; } @@ -583,7 +583,7 @@ private String toIndentedString(Object o) { openapiFields = new HashSet(Arrays.asList("href", "type", "uuid", "name", "bandwidth", "bandwidthCommit", "state", "change", "locations", "routingProtocol", "billing", "account", "project", "order", "changeLog", "useCase")); // a set of required properties/fields (JSON key names) - openapiRequiredFields = new HashSet(Arrays.asList("href", "type", "uuid", "name", "state", "change", "routingProtocol", "billing", "account", "project", "order", "changeLog", "useCase")); + openapiRequiredFields = new HashSet(Arrays.asList("href", "type", "uuid", "name", "state", "change", "routingProtocol", "billing", "account", "project", "changeLog", "useCase")); } /** @@ -643,8 +643,10 @@ public static void validateJsonElement(JsonElement jsonElement) throws IOExcepti InternetAccessAccount.validateJsonElement(jsonObj.get("account")); // validate the required field `project` Project.validateJsonElement(jsonObj.get("project")); - // validate the required field `order` - InternetAccessOrder.validateJsonElement(jsonObj.get("order")); + // validate the optional field `order` + if (jsonObj.get("order") != null && !jsonObj.get("order").isJsonNull()) { + InternetAccessOrder.validateJsonElement(jsonObj.get("order")); + } // validate the required field `changeLog` Changelog.validateJsonElement(jsonObj.get("changeLog")); // validate the required field `useCase` diff --git a/spec/services/fabricv4/oas3.patched/openapi.yaml b/spec/services/fabricv4/oas3.patched/openapi.yaml index 9c478a82..3ca737cf 100644 --- a/spec/services/fabricv4/oas3.patched/openapi.yaml +++ b/spec/services/fabricv4/oas3.patched/openapi.yaml @@ -16159,7 +16159,6 @@ components: - changeLog - href - name - - order - project - routingProtocol - state diff --git a/spec/services/fabricv4/patches/20260624-internet_access_service-order-required-skip.patch b/spec/services/fabricv4/patches/20260624-internet_access_service-order-required-skip.patch new file mode 100644 index 00000000..64256a63 --- /dev/null +++ b/spec/services/fabricv4/patches/20260624-internet_access_service-order-required-skip.patch @@ -0,0 +1,11 @@ +diff --git a/spec/services/fabricv4/oas3.patched/openapi.yaml b/spec/services/fabricv4/oas3.patched/openapi.yaml +--- a/spec/services/fabricv4/oas3.patched/openapi.yaml ++++ b/spec/services/fabricv4/oas3.patched/openapi.yaml +@@ -16160,7 +16160,6 @@ components: + - changeLog + - href + - name +- - order + - project + - routingProtocol + - state diff --git a/templates/services/fabricv4/libraries/okhttp-gson/additional_properties.mustache b/templates/services/fabricv4/libraries/okhttp-gson/additional_properties.mustache new file mode 100644 index 00000000..38d67e64 --- /dev/null +++ b/templates/services/fabricv4/libraries/okhttp-gson/additional_properties.mustache @@ -0,0 +1,48 @@ +{{#isAdditionalPropertiesTrue}} +{{^parent}} + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + private Map additionalProperties; + + /** + * Set the additional (undeclared) property with the specified name and value. + * If the property does not already exist, create it otherwise replace it. + * + * @param key name of the property + * @param value value of the property + * @return the {{classname}} instance itself + */ + public {{classname}} putAdditionalProperty(String key, Object value) { + if (this.additionalProperties == null) { + this.additionalProperties = new HashMap(); + } + this.additionalProperties.put(key, value); + return this; + } + + /** + * Return the additional (undeclared) property. + * + * @return a map of objects + */ + public Map getAdditionalProperties() { + return additionalProperties; + } + + /** + * Return the additional (undeclared) property with the specified name. + * + * @param key name of the property + * @return an object + */ + public Object getAdditionalProperty(String key) { + if (this.additionalProperties == null) { + return null; + } + return this.additionalProperties.get(key); + } +{{/parent}} +{{/isAdditionalPropertiesTrue}} diff --git a/templates/services/fabricv4/libraries/okhttp-gson/pojo.mustache b/templates/services/fabricv4/libraries/okhttp-gson/pojo.mustache new file mode 100644 index 00000000..f63f90a2 --- /dev/null +++ b/templates/services/fabricv4/libraries/okhttp-gson/pojo.mustache @@ -0,0 +1,598 @@ +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import {{invokerPackage}}.JSON; + +/** + * {{description}}{{^description}}{{classname}}{{/description}}{{#isDeprecated}} + * @deprecated{{/isDeprecated}} + */{{#isDeprecated}} +@Deprecated{{/isDeprecated}} +{{#swagger1AnnotationLibrary}} +{{#description}} +@ApiModel(description = "{{{.}}}") +{{/description}} +{{/swagger1AnnotationLibrary}} +{{#swagger2AnnotationLibrary}} +{{#description}} +@Schema(description = "{{{.}}}") +{{/description}} +{{/swagger2AnnotationLibrary}} +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} +{{#vendorExtensions.x-class-extra-annotation}} +{{{vendorExtensions.x-class-extra-annotation}}} +{{/vendorExtensions.x-class-extra-annotation}} +public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{#-last}} {{/-last}}{{/vendorExtensions.x-implements}}{ +{{#serializableModel}} + private static final long serialVersionUID = 1L; + +{{/serializableModel}} + {{#vars}} + {{#isEnum}} + {{^isContainer}} +{{>modelInnerEnum}} + + {{/isContainer}} + {{#isContainer}} + {{#mostInnerItems}} +{{>modelInnerEnum}} + + {{/mostInnerItems}} + {{/isContainer}} + {{/isEnum}} + public static final String SERIALIZED_NAME_{{nameInSnakeCase}} = "{{baseName}}"; + {{#withXml}} + @Xml{{#isXmlAttribute}}Attribute{{/isXmlAttribute}}{{^isXmlAttribute}}Element{{/isXmlAttribute}}(name = "{{items.xmlName}}{{^items.xmlName}}{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}{{/items.xmlName}}"{{#xmlNamespace}}, namespace = "{{.}}"{{/xmlNamespace}}) + {{#isXmlWrapped}} + @XmlElementWrapper(name = "{{xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}"{{#xmlNamespace}}, namespace = "{{.}}"{{/xmlNamespace}}) + {{/isXmlWrapped}} + {{/withXml}} + {{#deprecated}} + @Deprecated + {{/deprecated}} + @SerializedName(SERIALIZED_NAME_{{nameInSnakeCase}}) + {{#vendorExtensions.x-field-extra-annotation}} + {{{vendorExtensions.x-field-extra-annotation}}} + {{/vendorExtensions.x-field-extra-annotation}} + {{>nullable_var_annotations}}{{! prevent indent}} + {{#isDiscriminator}}protected{{/isDiscriminator}}{{^isDiscriminator}}private{{/isDiscriminator}} {{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}; + + {{/vars}} + public {{classname}}() { + {{#parent}} + {{#parcelableModel}} + super(); + {{/parcelableModel}} + {{/parent}} + {{#discriminator}} + {{#discriminator.isEnum}} +{{#readWriteVars}}{{#isDiscriminator}}{{#defaultValue}} + this.{{name}} = {{defaultValue}}; +{{/defaultValue}}{{/isDiscriminator}}{{/readWriteVars}} + {{/discriminator.isEnum}} + {{^discriminator.isEnum}} + this.{{{discriminatorName}}} = this.getClass().getSimpleName(); + {{/discriminator.isEnum}} + {{/discriminator}} + } + {{#vendorExtensions.x-has-readonly-properties}} + {{^withXml}} + + public {{classname}}( + {{#readOnlyVars}} + {{{datatypeWithEnum}}} {{name}}{{^-last}}, {{/-last}} + {{/readOnlyVars}} + ) { + this(); + {{#readOnlyVars}} + this.{{name}} = {{name}}; + {{/readOnlyVars}} + } + {{/withXml}} + {{/vendorExtensions.x-has-readonly-properties}} + {{#vars}} + + {{^isReadOnly}} + {{#deprecated}} + @Deprecated + {{/deprecated}} + public {{classname}} {{name}}({{>nullable_var_annotations}} {{{datatypeWithEnum}}} {{name}}) { + this.{{name}} = {{name}}; + return this; + } + {{#isArray}} + + public {{classname}} add{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) { + if (this.{{name}} == null) { + this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}}; + } + this.{{name}}.add({{name}}Item); + return this; + } + {{/isArray}} + {{#isMap}} + + public {{classname}} put{{nameInPascalCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) { + if (this.{{name}} == null) { + this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}}; + } + this.{{name}}.put(key, {{name}}Item); + return this; + } + {{/isMap}} + + {{/isReadOnly}} + /** + {{#description}} + * {{.}} + {{/description}} + {{^description}} + * Get {{name}} + {{/description}} + {{#minimum}} + * minimum: {{.}} + {{/minimum}} + {{#maximum}} + * maximum: {{.}} + {{/maximum}} + * @return {{name}} + {{#deprecated}} + * @deprecated + {{/deprecated}} + */ +{{#deprecated}} + @Deprecated +{{/deprecated}} + {{>nullable_var_annotations}}{{! prevent indent}} +{{#useBeanValidation}} +{{>beanValidation}} + +{{/useBeanValidation}} +{{#swagger1AnnotationLibrary}} + @ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}") +{{/swagger1AnnotationLibrary}} +{{#swagger2AnnotationLibrary}} + @Schema({{#example}}example = "{{{.}}}", {{/example}}requiredMode = {{#required}}Schema.RequiredMode.REQUIRED{{/required}}{{^required}}Schema.RequiredMode.NOT_REQUIRED{{/required}}, description = "{{{description}}}") +{{/swagger2AnnotationLibrary}} +{{#vendorExtensions.x-extra-annotation}} + {{{vendorExtensions.x-extra-annotation}}} +{{/vendorExtensions.x-extra-annotation}} + public {{{datatypeWithEnum}}} {{getter}}() { + return {{name}}; + } + + {{^isReadOnly}} +{{#vendorExtensions.x-setter-extra-annotation}} {{{vendorExtensions.x-setter-extra-annotation}}} +{{/vendorExtensions.x-setter-extra-annotation}}{{#deprecated}} @Deprecated +{{/deprecated}} public void {{setter}}({{>nullable_var_annotations}} {{{datatypeWithEnum}}} {{name}}) { + this.{{name}} = {{name}}; + } + {{/isReadOnly}} + + {{/vars}} +{{>libraries/okhttp-gson/additional_properties}} + + + @Override + public boolean equals(Object o) { + {{#useReflectionEqualsHashCode}} + return EqualsBuilder.reflectionEquals(this, o, false, null, true); + {{/useReflectionEqualsHashCode}} + {{^useReflectionEqualsHashCode}} + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + }{{#hasVars}} + {{classname}} {{classVarName}} = ({{classname}}) o; + return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} && + {{/-last}}{{/vars}}{{#isAdditionalPropertiesTrue}}{{^parent}}&& + Objects.equals(this.additionalProperties, {{classVarName}}.additionalProperties){{/parent}}{{/isAdditionalPropertiesTrue}}{{#parent}} && + super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}} + return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};{{/hasVars}} + {{/useReflectionEqualsHashCode}} + }{{#vendorExtensions.x-jackson-optional-nullable-helpers}} + + private static boolean equalsNullable(JsonNullable a, JsonNullable b) { + return a == b || (a != null && b != null && a.isPresent() && b.isPresent() && Objects.deepEquals(a.get(), b.get())); + }{{/vendorExtensions.x-jackson-optional-nullable-helpers}} + + @Override + public int hashCode() { + {{#useReflectionEqualsHashCode}} + return HashCodeBuilder.reflectionHashCode(this); + {{/useReflectionEqualsHashCode}} + {{^useReflectionEqualsHashCode}} + return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}{{#isAdditionalPropertiesTrue}}{{^parent}}{{#hasVars}}, {{/hasVars}}additionalProperties{{/parent}}{{/isAdditionalPropertiesTrue}}); + {{/useReflectionEqualsHashCode}} + }{{#vendorExtensions.x-jackson-optional-nullable-helpers}} + + private static int hashCodeNullable(JsonNullable a) { + if (a == null) { + return 1; + } + return a.isPresent() ? Arrays.deepHashCode(new Object[]{a.get()}) : 31; + }{{/vendorExtensions.x-jackson-optional-nullable-helpers}} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}} + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + {{/parent}} + {{#vars}} + sb.append(" {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n"); + {{/vars}} +{{#isAdditionalPropertiesTrue}} +{{^parent}} + sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); +{{/parent}} +{{/isAdditionalPropertiesTrue}} + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +{{#parcelableModel}} + + public void writeToParcel(Parcel out, int flags) { +{{#model}} +{{#isArray}} + out.writeList(this); +{{/isArray}} +{{^isArray}} +{{#parent}} + super.writeToParcel(out, flags); +{{/parent}} +{{#vars}} + out.writeValue({{name}}); +{{/vars}} +{{/isArray}} +{{/model}} + } + + {{classname}}(Parcel in) { +{{#isArray}} + in.readTypedList(this, {{arrayModelType}}.CREATOR); +{{/isArray}} +{{^isArray}} +{{#parent}} + super(in); +{{/parent}} +{{#vars}} +{{#isPrimitiveType}} + {{name}} = ({{{datatypeWithEnum}}})in.readValue(null); +{{/isPrimitiveType}} +{{^isPrimitiveType}} + {{name}} = ({{{datatypeWithEnum}}})in.readValue({{complexType}}.class.getClassLoader()); +{{/isPrimitiveType}} +{{/vars}} +{{/isArray}} + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<{{classname}}> CREATOR = new Parcelable.Creator<{{classname}}>() { + public {{classname}} createFromParcel(Parcel in) { +{{#model}} +{{#isArray}} + {{classname}} result = new {{classname}}(); + result.addAll(in.readArrayList({{arrayModelType}}.class.getClassLoader())); + return result; +{{/isArray}} +{{^isArray}} + return new {{classname}}(in); +{{/isArray}} +{{/model}} + } + public {{classname}}[] newArray(int size) { + return new {{classname}}[size]; + } + }; +{{/parcelableModel}} + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + {{#hasVars}} + openapiFields = new HashSet(Arrays.asList({{#allVars}}"{{baseName}}"{{^-last}}, {{/-last}}{{/allVars}})); + {{/hasVars}} + {{^hasVars}} + openapiFields = new HashSet(0); + {{/hasVars}} + + // a set of required properties/fields (JSON key names) + {{#hasRequired}} + openapiRequiredFields = new HashSet(Arrays.asList({{#requiredVars}}"{{baseName}}"{{^-last}}, {{/-last}}{{/requiredVars}})); + {{/hasRequired}} + {{^hasRequired}} + openapiRequiredFields = new HashSet(0); + {{/hasRequired}} + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to {{classname}} + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!{{classname}}.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in {{{classname}}} is not found in the empty JSON string", {{classname}}.openapiRequiredFields.toString())); + } + } + {{^hasChildren}} + {{^isAdditionalPropertiesTrue}} + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!{{classname}}.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `{{classname}}` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + {{/isAdditionalPropertiesTrue}} + {{#requiredVars}} + {{#-first}} + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : {{classname}}.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + {{/-first}} + {{/requiredVars}} + {{/hasChildren}} + {{^discriminator}} + {{#hasVars}} + JsonObject jsonObj = jsonElement.getAsJsonObject(); + {{/hasVars}} + {{#vars}} + {{#isArray}} + {{#items.isModel}} + {{#required}} + // ensure the json data is an array + if (!jsonObj.get("{{{baseName}}}").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `{{{baseName}}}` to be an array in the JSON string but got `%s`", jsonObj.get("{{{baseName}}}").toString())); + } + + JsonArray jsonArray{{name}} = jsonObj.getAsJsonArray("{{{baseName}}}"); + // validate the required field `{{{baseName}}}` (array) + for (int i = 0; i < jsonArray{{name}}.size(); i++) { + {{{items.dataType}}}.validateJsonElement(jsonArray{{name}}.get(i)); + }; + {{/required}} + {{^required}} + if (jsonObj.get("{{{baseName}}}") != null && !jsonObj.get("{{{baseName}}}").isJsonNull()) { + JsonArray jsonArray{{name}} = jsonObj.getAsJsonArray("{{{baseName}}}"); + if (jsonArray{{name}} != null) { + // ensure the json data is an array + if (!jsonObj.get("{{{baseName}}}").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `{{{baseName}}}` to be an array in the JSON string but got `%s`", jsonObj.get("{{{baseName}}}").toString())); + } + + // validate the optional field `{{{baseName}}}` (array) + for (int i = 0; i < jsonArray{{name}}.size(); i++) { + {{{items.dataType}}}.validateJsonElement(jsonArray{{name}}.get(i)); + }; + } + } + {{/required}} + {{/items.isModel}} + {{^items.isModel}} + {{^required}} + // ensure the optional json data is an array if present + if (jsonObj.get("{{{baseName}}}") != null && !jsonObj.get("{{{baseName}}}").isJsonNull() && !jsonObj.get("{{{baseName}}}").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `{{{baseName}}}` to be an array in the JSON string but got `%s`", jsonObj.get("{{{baseName}}}").toString())); + } + {{/required}} + {{#required}} + // ensure the required json array is present + if (jsonObj.get("{{{baseName}}}") == null) { + throw new IllegalArgumentException("Expected the field `linkedContent` to be an array in the JSON string but got `null`"); + } else if (!jsonObj.get("{{{baseName}}}").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `{{{baseName}}}` to be an array in the JSON string but got `%s`", jsonObj.get("{{{baseName}}}").toString())); + } + {{/required}} + {{/items.isModel}} + {{/isArray}} + {{^isContainer}} + {{#isString}} + if ({{#notRequiredOrIsNullable}}(jsonObj.get("{{{baseName}}}") != null && !jsonObj.get("{{{baseName}}}").isJsonNull()) && {{/notRequiredOrIsNullable}}!jsonObj.get("{{{baseName}}}").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `{{{baseName}}}` to be a primitive type in the JSON string but got `%s`", jsonObj.get("{{{baseName}}}").toString())); + } + {{/isString}} + {{#isModel}} + {{#required}} + // validate the required field `{{{baseName}}}` + {{{dataType}}}.validateJsonElement(jsonObj.get("{{{baseName}}}")); + {{/required}} + {{^required}} + // validate the optional field `{{{baseName}}}` + if (jsonObj.get("{{{baseName}}}") != null && !jsonObj.get("{{{baseName}}}").isJsonNull()) { + {{{dataType}}}.validateJsonElement(jsonObj.get("{{{baseName}}}")); + } + {{/required}} + {{/isModel}} + {{#isEnum}} + {{#required}} + // validate the required field `{{{baseName}}}` + {{{datatypeWithEnum}}}.validateJsonElement(jsonObj.get("{{{baseName}}}")); + {{/required}} + {{^required}} + // validate the optional field `{{{baseName}}}` + if (jsonObj.get("{{{baseName}}}") != null && !jsonObj.get("{{{baseName}}}").isJsonNull()) { + {{{datatypeWithEnum}}}.validateJsonElement(jsonObj.get("{{{baseName}}}")); + } + {{/required}} + {{/isEnum}} + {{#isEnumRef}} + {{#required}} + // validate the required field `{{{baseName}}}` + {{{dataType}}}.validateJsonElement(jsonObj.get("{{{baseName}}}")); + {{/required}} + {{^required}} + // validate the optional field `{{{baseName}}}` + if (jsonObj.get("{{{baseName}}}") != null && !jsonObj.get("{{{baseName}}}").isJsonNull()) { + {{{dataType}}}.validateJsonElement(jsonObj.get("{{{baseName}}}")); + } + {{/required}} + {{/isEnumRef}} + {{/isContainer}} + {{/vars}} + {{/discriminator}} + {{#hasChildren}} + {{#discriminator}} + + String discriminatorValue = jsonElement.getAsJsonObject().get("{{{propertyBaseName}}}").getAsString(); + switch (discriminatorValue) { + {{#mappedModels}} + case "{{mappingName}}": + {{modelName}}.validateJsonElement(jsonElement); + break; + {{/mappedModels}} + default: + throw new IllegalArgumentException(String.format(Locale.ROOT, "The value of the `{{{propertyBaseName}}}` field `%s` does not match any key defined in the discriminator's mapping.", discriminatorValue)); + } + {{/discriminator}} + {{/hasChildren}} + } + +{{^hasChildren}} + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!{{classname}}.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes '{{classname}}' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter<{{classname}}> thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get({{classname}}.class)); + + return (TypeAdapter) new TypeAdapter<{{classname}}>() { + @Override + public void write(JsonWriter out, {{classname}} value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + {{#isAdditionalPropertiesTrue}} + obj.remove("additionalProperties"); + // serialize additional properties + if (value.getAdditionalProperties() != null) { + for (Map.Entry entry : value.getAdditionalProperties().entrySet()) { + if (entry.getValue() instanceof String) + obj.addProperty(entry.getKey(), (String) entry.getValue()); + else if (entry.getValue() instanceof Number) + obj.addProperty(entry.getKey(), (Number) entry.getValue()); + else if (entry.getValue() instanceof Boolean) + obj.addProperty(entry.getKey(), (Boolean) entry.getValue()); + else if (entry.getValue() instanceof Character) + obj.addProperty(entry.getKey(), (Character) entry.getValue()); + else { + JsonElement jsonElement = gson.toJsonTree(entry.getValue()); + if (jsonElement.isJsonArray()) { + obj.add(entry.getKey(), jsonElement.getAsJsonArray()); + } else { + obj.add(entry.getKey(), jsonElement.getAsJsonObject()); + } + } + } + } + {{/isAdditionalPropertiesTrue}} + elementAdapter.write(out, obj); + } + + @Override + public {{classname}} read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + {{#isAdditionalPropertiesTrue}} + JsonObject jsonObj = jsonElement.getAsJsonObject(); + // store additional fields in the deserialized instance + {{classname}} instance = thisAdapter.fromJsonTree(jsonObj); + for (Map.Entry entry : jsonObj.entrySet()) { + if (!openapiFields.contains(entry.getKey())) { + if (entry.getValue().isJsonPrimitive()) { // primitive type + if (entry.getValue().getAsJsonPrimitive().isString()) + instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsString()); + else if (entry.getValue().getAsJsonPrimitive().isNumber()) + instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsNumber()); + else if (entry.getValue().getAsJsonPrimitive().isBoolean()) + instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsBoolean()); + else + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` has unknown primitive type. Value: %s", entry.getKey(), entry.getValue().toString())); + } else if (entry.getValue().isJsonArray()) { + instance.putAdditionalProperty(entry.getKey(), gson.fromJson(entry.getValue(), List.class)); + } else { // JSON object + instance.putAdditionalProperty(entry.getKey(), gson.fromJson(entry.getValue(), HashMap.class)); + } + } + } + return instance; + {{/isAdditionalPropertiesTrue}} + {{^isAdditionalPropertiesTrue}} + return thisAdapter.fromJsonTree(jsonElement); + {{/isAdditionalPropertiesTrue}} + } + + }.nullSafe(); + } + } +{{/hasChildren}} + + /** + * Create an instance of {{classname}} given an JSON string + * + * @param jsonString JSON string + * @return An instance of {{classname}} + * @throws IOException if the JSON string is invalid with respect to {{classname}} + */ + public static {{{classname}}} fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, {{{classname}}}.class); + } + + /** + * Convert an instance of {{classname}} to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +}