From c953d1298cc8f00d8c6aec63dc428b8c43ae9cfb Mon Sep 17 00:00:00 2001 From: dshelbyo Date: Thu, 29 Nov 2018 17:56:20 +0000 Subject: [PATCH] Releasing version 1.3.2 --- CHANGELOG.md | 13 +- LICENSE.txt | 13 +- .../bmc-apache-connector-provider/pom.xml | 4 +- bmc-addons/pom.xml | 2 +- bmc-audit/pom.xml | 4 +- bmc-bom/pom.xml | 30 +-- bmc-common/pom.xml | 2 +- .../src/main/java/com/oracle/bmc/Realm.java | 23 ++ .../src/main/java/com/oracle/bmc/Region.java | 115 ++++++---- .../src/main/java/com/oracle/bmc/Service.java | 7 +- .../main/java/com/oracle/bmc/Services.java | 6 +- ...incipalsAuthenticationDetailsProvider.java | 2 + .../com/oracle/bmc/auth/RegionProvider.java | 4 + .../bmc/auth/StringPrivateKeySupplier.java | 4 +- .../auth/URLBasedX509CertificateSupplier.java | 57 +++-- .../oracle/bmc/auth/internal/AuthUtils.java | 25 +- .../internal/ForwardingX509Certificate.java | 213 ++++++++++++++++++ .../X509CertificateWithOriginalPem.java | 40 ++++ .../auth/internal/X509FederationClient.java | 14 -- .../bmc/http/internal/ResponseHelper.java | 35 ++- .../signing/internal/BouncyCastleHelper.java | 7 +- .../PEMFileRSAPrivateKeySupplier.java | 1 - .../DefaultEndpointConfiguration.java | 93 ++++++++ .../oracle/bmc/internal/EndpointBuilder.java | 77 +++++++ .../internal/AbstractResponseIterator.java | 2 +- .../paginator/internal/ResponseIterator.java | 2 - .../internal/ResponseRecordIterator.java | 2 +- .../resources/com/oracle/bmc/sdk.properties | 3 +- .../test/java/com/oracle/bmc/RealmTest.java | 22 ++ .../test/java/com/oracle/bmc/RegionTest.java | 57 ++++- .../java/com/oracle/bmc/ServicesTest.java | 37 ++- .../internal/ExplicitlySetFilterTest.java | 36 ++- .../bmc/http/internal/ResponseHelperTest.java | 40 ++++ .../PEMFileRSAPrivateKeySupplierTest.java | 2 - .../DefaultEndpointConfigurationTest.java | 55 +++++ .../bmc/internal/EndpointBuilderTest.java | 63 ++++++ .../bmc/util/internal/HttpUtilsTest.java | 8 + bmc-containerengine/pom.xml | 4 +- bmc-core/pom.xml | 4 +- bmc-database/pom.xml | 4 +- bmc-dns/pom.xml | 4 +- bmc-email/pom.xml | 4 +- bmc-examples/pom.xml | 4 +- .../java/ObjectStorageGetBucketExample.java | 109 +++++++++ .../src/main/java/RawRestCallExample.java | 5 +- bmc-filestorage/pom.xml | 4 +- bmc-full/pom.xml | 4 +- bmc-identity/pom.xml | 4 +- bmc-keymanagement/pom.xml | 4 +- bmc-loadbalancer/pom.xml | 4 +- .../bmc-objectstorage-combined/pom.xml | 6 +- .../bmc-objectstorage-extensions/pom.xml | 6 +- .../bmc-objectstorage-generated/pom.xml | 4 +- .../internal/http/GetBucketConverter.java | 9 + .../bmc/objectstorage/model/Bucket.java | 42 +++- .../requests/GetBucketRequest.java | 48 ++++ bmc-objectstorage/pom.xml | 2 +- bmc-resourcesearch/pom.xml | 4 +- bmc-shaded/bmc-shaded-full/pom.xml | 2 +- bmc-shaded/pom.xml | 2 +- pom.xml | 27 ++- 61 files changed, 1226 insertions(+), 204 deletions(-) create mode 100644 bmc-common/src/main/java/com/oracle/bmc/Realm.java create mode 100644 bmc-common/src/main/java/com/oracle/bmc/auth/internal/ForwardingX509Certificate.java create mode 100644 bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509CertificateWithOriginalPem.java create mode 100644 bmc-common/src/main/java/com/oracle/bmc/internal/DefaultEndpointConfiguration.java create mode 100644 bmc-common/src/main/java/com/oracle/bmc/internal/EndpointBuilder.java create mode 100644 bmc-common/src/test/java/com/oracle/bmc/RealmTest.java create mode 100644 bmc-common/src/test/java/com/oracle/bmc/internal/DefaultEndpointConfigurationTest.java create mode 100644 bmc-common/src/test/java/com/oracle/bmc/internal/EndpointBuilderTest.java create mode 100644 bmc-examples/src/main/java/ObjectStorageGetBucketExample.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 60968bde225..4b0c3a8e410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - N/A +## 1.3.2 - 2018-11-29 +### Added +- Support for getting bucket statistics in the Object Storage service + +### Fixed +- Storage service for copying volume backups across regions is now enabled +- Objects can now be retrieved from Object Storage even if their content type is invalid + ## 1.3.1 - 2018-11-15 ### Added - Support for VCN transit routing in the Networking service @@ -44,15 +52,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - Support for generating and downloading wallets in the Database service - Support for creating a standalone backup from an on-premises database in the Database service - Support for db version and additional connection strings in the Autonomous Transaction Processing and Autonomous Data Warehouse resources of the Database service -- Support for copying volume backups across regions in the Block Storage service (please see Known issue) +- Support for copying volume backups across regions in the Block Storage service - Support for deleting compartments in the Identity service - Support for reboot migration for virtual machines in the Compute service - Support for Instance Pools and Instance Configurations in the Compute service - `lengthPerUploadPart` provides a simpler way to control the size of parts when using Upload Manager -### Known issue -- Block Storage service for copying volume backups across regions is not yet enabled - ### Breaking change - The `dbDataSizeInMBs` field in the `com.oracle.bmc.database.model.Backup` and `com.oracle.bmc.database.model.BackupSummary` classes was renamed to `databaseSizeInGBs`, and its type was changed from `Integer` to `Double` - Before diff --git a/LICENSE.txt b/LICENSE.txt index 63bc0c882eb..a115ecfb483 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,10 @@ Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -This software is dual-licensed to you under the Universal Permissive License (UPL) and Apache License 2.0.  See below for license terms.  You may choose either license, or both. - ____________________________ + +This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 or Apache License 2.0. See below for license terms. You may choose either license. + +____________________________ + The Universal Permissive License (UPL), Version 1.0 Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. @@ -27,7 +30,7 @@ Apache License Version 2.0, January 2004 -http://www.apache.org/licenses/ +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. @@ -46,9 +49,9 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. -You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. diff --git a/bmc-addons/bmc-apache-connector-provider/pom.xml b/bmc-addons/bmc-apache-connector-provider/pom.xml index d3c93c8a8a2..66f4ac16d33 100644 --- a/bmc-addons/bmc-apache-connector-provider/pom.xml +++ b/bmc-addons/bmc-apache-connector-provider/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk-addons - 1.3.1 + 1.3.2 ../pom.xml @@ -37,7 +37,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-addons/pom.xml b/bmc-addons/pom.xml index 45e5ef0b793..a29a0303d33 100644 --- a/bmc-addons/pom.xml +++ b/bmc-addons/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml diff --git a/bmc-audit/pom.xml b/bmc-audit/pom.xml index a2b6c136ca6..84b0186cd8f 100644 --- a/bmc-audit/pom.xml +++ b/bmc-audit/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-bom/pom.xml b/bmc-bom/pom.xml index 72685590a73..d6b5d384514 100644 --- a/bmc-bom/pom.xml +++ b/bmc-bom/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml oci-java-sdk-bom @@ -19,86 +19,86 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-audit - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-containerengine - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-core - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-database - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-dns - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-email - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-filestorage - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-identity - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-loadbalancer - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-objectstorage - 1.3.1 + 1.3.2 false com.oracle.oci.sdk oci-java-sdk-resourcesearch false - 1.3.1 + 1.3.2 com.oracle.oci.sdk false oci-java-sdk-addons-apache - 1.3.1 + 1.3.2 com.oracle.oci.sdk oci-java-sdk-keymanagement - 1.3.1 + 1.3.2 false diff --git a/bmc-common/pom.xml b/bmc-common/pom.xml index 32b26b6b020..1b1a6333313 100644 --- a/bmc-common/pom.xml +++ b/bmc-common/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml diff --git a/bmc-common/src/main/java/com/oracle/bmc/Realm.java b/bmc-common/src/main/java/com/oracle/bmc/Realm.java new file mode 100644 index 00000000000..d0e2cf8380f --- /dev/null +++ b/bmc-common/src/main/java/com/oracle/bmc/Realm.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * Enumeration of all Identity realms. + *

+ * Accounts (tenancies) are per Realm. + */ +@RequiredArgsConstructor +public enum Realm { + OC1("oc1"); + + @Getter + /** + * The id of the realm. + */ + private final String realmId; +} diff --git a/bmc-common/src/main/java/com/oracle/bmc/Region.java b/bmc-common/src/main/java/com/oracle/bmc/Region.java index b7522a2d480..a032b907895 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/Region.java +++ b/bmc-common/src/main/java/com/oracle/bmc/Region.java @@ -3,17 +3,15 @@ */ package com.oracle.bmc; -import java.io.InputStream; import java.util.HashMap; import java.util.Map; -import java.util.Properties; import com.google.common.base.Optional; +import com.oracle.bmc.internal.EndpointBuilder; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; /** * Enumeration of all of the known Regions that can be contacted. @@ -23,44 +21,51 @@ @Slf4j @RequiredArgsConstructor public enum Region { - US_PHOENIX_1("us-phoenix-1", "phx"), - US_ASHBURN_1("us-ashburn-1", "iad"), - EU_FRANKFURT_1("eu-frankfurt-1", "fra"), - UK_LONDON_1("uk-london-1", "lhr"); + // OC1 + // regionCode for FRA shouldn't be needed, but left for backwards compat + EU_FRANKFURT_1("eu-frankfurt-1", "fra", Realm.OC1), + // regionCode for LHR shouldn't be needed, but left for backwards compat + UK_LONDON_1("uk-london-1", "lhr", Realm.OC1), + US_ASHBURN_1("us-ashburn-1", "iad", Realm.OC1), + US_PHOENIX_1("us-phoenix-1", "phx", Realm.OC1); private static final Map> SERVICE_TO_REGION_ENDPOINTS = new HashMap<>(); - private static final String DEFAULT_ENDPOINT_FORMAT; - - static { - Properties properties = new Properties(); - try (InputStream propertyStream = - Region.class - .getClassLoader() - .getResourceAsStream("com/oracle/bmc/sdk.properties")) { - properties.load(propertyStream); - } catch (Exception e) { - throw new IllegalStateException("Failed to load required properties file", e); - } - - DEFAULT_ENDPOINT_FORMAT = properties.getProperty("endpoint.defaultFormat"); - if (DEFAULT_ENDPOINT_FORMAT == null) { - throw new IllegalStateException("Default endpoint format must be available"); - } - - LOG.info("Using default endpoint format of '{}'", DEFAULT_ENDPOINT_FORMAT); - } - /** * Get the region ID. */ @Getter private final String regionId; + /** + * The region code obtained from the 'region' field of instance metadata. This + * does not match the regionId in us-phoenix-1 and us-ashburn-1, but does in all + * other regions. + */ + @Deprecated private final Optional regionCode; + + /** + * Get the realm this region belongs to. + */ + @Getter private final Realm realm; + + private Region(String regionId, Realm realm) { + this(regionId, Optional.absent(), realm); + } + + private Region(String regionId, String regionCode, Realm realm) { + this(regionId, Optional.of(regionCode), realm); + } + /** * Get the region code. + * @Deprecated Do not use regionCode anymore. Use {@link #getRegionId()} to retrieve + * the canonical region ID. */ - @Getter private final String regionCode; + @Deprecated + public String getRegionCode() { + return regionCode.or(regionId); + } /** * Resolves a service name to its endpoint in the region, if available. @@ -74,7 +79,7 @@ public synchronized Optional getEndpoint(Service service) { if (!SERVICE_TO_REGION_ENDPOINTS.containsKey(service.getServiceName())) { HashMap endpoints = new HashMap<>(); for (Region region : Region.values()) { - String endpoint = formatDefaultRegionEndpoint(service, region.regionId); + String endpoint = formatDefaultRegionEndpoint(service, region); endpoints.put(region, endpoint); } SERVICE_TO_REGION_ENDPOINTS.put(service.getServiceName(), endpoints); @@ -95,18 +100,40 @@ public synchronized Optional getEndpoint(Service service) { * a URL that follows the default format. * * @param service The service. + * @param region The region. + * @return The endpoint. + */ + public static String formatDefaultRegionEndpoint(Service service, Region region) { + return EndpointBuilder.createEndpoint(service, region); + } + + /** + * Creates a default endpoint URL for the given service in the given region. + * + *

+ * Note, the regionId is not validated against known regions, this just creates + * a URL that follows the default format. + *

+ * This method uses a realm of {@link Realm#OC1} if the region cannot be determined. + * + * @param service The service. * @param regionId The region ID. * @return The endpoint. */ public static String formatDefaultRegionEndpoint(Service service, String regionId) { - if (StringUtils.isNotBlank(service.getServiceEndpointTemplate())) { - return service.getServiceEndpointTemplate().replace("{region}", regionId); + // try to get a real region first + Optional maybeRegion = maybeFromRegionId(regionId); + if (maybeRegion.isPresent()) { + return formatDefaultRegionEndpoint(service, maybeRegion.get()); } - return String.format(DEFAULT_ENDPOINT_FORMAT, service.getServiceEndpointPrefix(), regionId); + + // else we need to fall back to OC1 SLD + LOG.debug("Unknown regionId '{}', will assume it's in Realm OC1", regionId); + return EndpointBuilder.createEndpoint(service, regionId, Realm.OC1); } /** - * Returns the region enum from the public region ID. Throws + * Returns the region enum from the canonical public region ID. Throws * IllegalArgumentException if the region ID is not known. * * @param regionId @@ -114,12 +141,20 @@ public static String formatDefaultRegionEndpoint(Service service, String regionI * @return The enum value. */ public static Region fromRegionId(String regionId) { + Optional maybeRegion = maybeFromRegionId(regionId); + if (maybeRegion.isPresent()) { + return maybeRegion.get(); + } + throw new IllegalArgumentException("Unknown regionId: " + regionId); + } + + private static Optional maybeFromRegionId(String regionId) { for (Region region : Region.values()) { if (region.regionId.equals(regionId)) { - return region; + return Optional.of(region); } } - throw new IllegalArgumentException("Unknown regionId: " + regionId); + return Optional.absent(); } /** @@ -129,10 +164,12 @@ public static Region fromRegionId(String regionId) { * @param regionCode * The region code. * @return The enum value. + * @deprecated use {@link #fromRegionId(String)} and provide the canonical region ID. */ + @Deprecated public static Region fromRegionCode(String regionCode) { for (Region region : Region.values()) { - if (region.regionCode.compareToIgnoreCase(regionCode) == 0) { + if (region.getRegionCode().compareToIgnoreCase(regionCode) == 0) { return region; } } @@ -146,10 +183,12 @@ public static Region fromRegionCode(String regionCode) { * @param regionCodeOrId * The region code or id. * @return The enum value. + * @deprecated use {@link #fromRegionId(String)} and provide the canonical region ID. */ + @Deprecated public static Region fromRegionCodeOrId(String regionCodeOrId) { for (Region region : Region.values()) { - if (region.regionCode.compareToIgnoreCase(regionCodeOrId) == 0 + if (region.getRegionCode().compareToIgnoreCase(regionCodeOrId) == 0 || region.regionId.compareToIgnoreCase(regionCodeOrId) == 0) { return region; } diff --git a/bmc-common/src/main/java/com/oracle/bmc/Service.java b/bmc-common/src/main/java/com/oracle/bmc/Service.java index 4e8be01dabd..849b8183dbc 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/Service.java +++ b/bmc-common/src/main/java/com/oracle/bmc/Service.java @@ -12,7 +12,7 @@ public interface Service { /** - * The unique service name, ex "BLOCKSTORAGE" + * The unique service name, ex "BLOCKSTORAGE". Must not be null. */ String getServiceName(); @@ -24,7 +24,10 @@ public interface Service { /** * The service endpoint template that will be used, ex - * "{region}.service.oci.oraclecloud.com" + * "{serviceEndpointPrefix}.{region}.service.oci.oraclecloud.com". + *

+ * This overrides the template used in {@link DefaultEndpointConfiguration}, but + * can still use the same variables. */ String getServiceEndpointTemplate(); } diff --git a/bmc-common/src/main/java/com/oracle/bmc/Services.java b/bmc-common/src/main/java/com/oracle/bmc/Services.java index 8a8bc4ee627..16c6ad81bcd 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/Services.java +++ b/bmc-common/src/main/java/com/oracle/bmc/Services.java @@ -8,6 +8,8 @@ import lombok.Builder; import lombok.Value; +import lombok.extern.slf4j.Slf4j; + import org.apache.commons.lang3.Validate; /** @@ -16,8 +18,8 @@ * This serves to ensure conflicting definitions of services * don't get created. */ +@Slf4j public class Services { - private static final Map SERVICE_CACHE = new HashMap<>(); /** @@ -54,6 +56,7 @@ private static synchronized Service create( final String serviceEndpointPrefix, final String serviceEndpointTemplate) { Validate.notBlank(serviceName); + final Service newInstance = new BasicService(serviceName, serviceEndpointPrefix, serviceEndpointTemplate); if (SERVICE_CACHE.containsKey(serviceName)) { @@ -68,6 +71,7 @@ private static synchronized Service create( existing, newInstance)); } + LOG.info("Registering new service: {}", newInstance); SERVICE_CACHE.put(serviceName, newInstance); return newInstance; } diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/InstancePrincipalsAuthenticationDetailsProvider.java b/bmc-common/src/main/java/com/oracle/bmc/auth/InstancePrincipalsAuthenticationDetailsProvider.java index 353a1618d2a..bb9ba39dd5d 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/auth/InstancePrincipalsAuthenticationDetailsProvider.java +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/InstancePrincipalsAuthenticationDetailsProvider.java @@ -127,6 +127,8 @@ public InstancePrincipalsAuthenticationDetailsProvider build() { String regionStr = base.path("region").request(MediaType.TEXT_PLAIN).get(String.class); + // TODO: we should start using 'canonicalRegionName' instead of 'region' and call + // Region.fromRegionId, and fall back to 'region' only for backwards compat. region = Region.fromRegionCodeOrId(regionStr); Optional endpoint = region.getEndpoint(SERVICE); diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/RegionProvider.java b/bmc-common/src/main/java/com/oracle/bmc/auth/RegionProvider.java index 89dd8fd8dd0..726484bc102 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/auth/RegionProvider.java +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/RegionProvider.java @@ -7,6 +7,10 @@ /** * A region provider has the API to return the region. + *

+ * An {@link AbstractAuthenticationDetailsProvider} can also implements this interface + * as a way to bootstrap a client during initialization using the Region returned + * by this interface. */ public interface RegionProvider { /** diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/StringPrivateKeySupplier.java b/bmc-common/src/main/java/com/oracle/bmc/auth/StringPrivateKeySupplier.java index da631e70db3..0d3e8d7867f 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/auth/StringPrivateKeySupplier.java +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/StringPrivateKeySupplier.java @@ -3,13 +3,13 @@ */ package com.oracle.bmc.auth; -import com.google.common.base.Charsets; import com.google.common.base.Supplier; import lombok.RequiredArgsConstructor; import lombok.ToString; import org.apache.commons.io.IOUtils; import java.io.InputStream; +import java.nio.charset.StandardCharsets; /** * Supplier for private key in String format @@ -22,6 +22,6 @@ public class StringPrivateKeySupplier implements Supplier { @Override public InputStream get() { - return IOUtils.toInputStream(privateKey, Charsets.UTF_8); + return IOUtils.toInputStream(privateKey, StandardCharsets.UTF_8); } } diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/URLBasedX509CertificateSupplier.java b/bmc-common/src/main/java/com/oracle/bmc/auth/URLBasedX509CertificateSupplier.java index 5203aad37ce..493bdb3b56b 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/auth/URLBasedX509CertificateSupplier.java +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/URLBasedX509CertificateSupplier.java @@ -3,25 +3,45 @@ */ package com.oracle.bmc.auth; -import com.oracle.bmc.http.signing.internal.PEMFileRSAPrivateKeySupplier; -import com.oracle.bmc.util.StreamUtils; - -import javax.security.auth.Refreshable; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.concurrent.atomic.AtomicReference; +import javax.security.auth.Refreshable; + +import org.apache.commons.io.IOUtils; + +import com.oracle.bmc.auth.internal.X509CertificateWithOriginalPem; +import com.oracle.bmc.http.signing.internal.PEMFileRSAPrivateKeySupplier; + +import lombok.extern.slf4j.Slf4j; + /** * {@link X509CertificateSupplier} implementation that reads both certificate and private key * off of URL. This class also provides a way to manually refresh the certificate and * private key at any point. */ +@Slf4j public class URLBasedX509CertificateSupplier implements X509CertificateSupplier, Refreshable { + /** + * Provide a way for the application environment to disable the X509 workaround by setting + * a system property to "true". On the command line, this can be done using + * `-Doci.sdk.experimental.suppressX509Workaround=true` + */ + private static final boolean EXPERIMENTAL_SUPPRESS_X509_WORKAROUND = + Boolean.getBoolean("oci.sdk.experimental.suppressX509Workaround"); + + static { + LOG.info("suppressX509Workaround flag set to {}", EXPERIMENTAL_SUPPRESS_X509_WORKAROUND); + } + /** * The certificate and the private key of certificate. */ @@ -93,10 +113,18 @@ public X509Certificate getCertificate() { */ @Override public void refresh() { - X509Certificate certificate = readCertificate(certificateUrl); + String rawCertificate = readRawCertificate(certificateUrl); + X509Certificate certificate = readCertificate(rawCertificate); RSAPrivateKey privateKey = readPrivateKey(privateKeyUrl, privateKeyPassphraseCharacters); - - this.certificateAndKeyPair.set(new CertificateAndPrivateKeyPair(certificate, privateKey)); + if (EXPERIMENTAL_SUPPRESS_X509_WORKAROUND) { + this.certificateAndKeyPair.set( + new CertificateAndPrivateKeyPair(certificate, privateKey)); + } else { + X509CertificateWithOriginalPem wrappedCertificate = + new X509CertificateWithOriginalPem(certificate, rawCertificate); + this.certificateAndKeyPair.set( + new CertificateAndPrivateKeyPair(wrappedCertificate, privateKey)); + } } /** @@ -113,18 +141,21 @@ public boolean isCurrent() { * @param certificateUrl the certificate url * @return the certificate */ - private static X509Certificate readCertificate(URL certificateUrl) { - InputStream is = null; + private static X509Certificate readCertificate(String certificate) { try { - is = certificateUrl.openStream(); CertificateFactory factory = CertificateFactory.getInstance("X.509"); - return (X509Certificate) factory.generateCertificate(is); + return (X509Certificate) + factory.generateCertificate(new ByteArrayInputStream(certificate.getBytes())); } catch (CertificateException e) { throw new IllegalArgumentException("Invalid certificate.", e); + } + } + + private static String readRawCertificate(URL certificateUrl) { + try (InputStream is = certificateUrl.openStream()) { + return IOUtils.toString(is, StandardCharsets.UTF_8); } catch (IOException e) { throw new IllegalArgumentException("Open stream of certificate failed.", e); - } finally { - StreamUtils.closeQuietly(is); } } diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/internal/AuthUtils.java b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/AuthUtils.java index c9b14b2b2d5..da2354d5ea2 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/auth/internal/AuthUtils.java +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/AuthUtils.java @@ -41,7 +41,6 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class AuthUtils { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); /** @@ -54,8 +53,9 @@ public class AuthUtils { public static String getFingerPrint(X509Certificate certificate) { Preconditions.checkNotNull(certificate); try { + final byte[] encodedCertificate = getEncodedCertificate(certificate); MessageDigest md = MessageDigest.getInstance("SHA-1"); - md.update(certificate.getEncoded()); + md.update(encodedCertificate); String fingerprint = getHex(md.digest()); return formatStringWithSeparator(fingerprint); @@ -198,7 +198,26 @@ public static String base64EncodeNoChunking(RSAPublicKey publicKey) { public static String base64EncodeNoChunking(X509Certificate certificate) throws CertificateEncodingException { return new String( - Base64.encodeBase64(certificate.getEncoded(), false), StandardCharsets.UTF_8); + Base64.encodeBase64(getEncodedCertificate(certificate), false), + StandardCharsets.UTF_8); + } + + private static byte[] getEncodedCertificate(X509Certificate certificate) + throws CertificateEncodingException { + if (certificate instanceof X509CertificateWithOriginalPem) { + return getEncodedCertificateFromPem( + ((X509CertificateWithOriginalPem) certificate).getPemEncodedCertificate()); + } else { + return certificate.getEncoded(); + } + } + + private static byte[] getEncodedCertificateFromPem(String pemEncodedCertificate) { + // strip out header and footer + return Base64.decodeBase64( + pemEncodedCertificate + .replace("-----BEGIN CERTIFICATE-----", "") + .replace("-----END CERTIFICATE-----", "")); } /** diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/internal/ForwardingX509Certificate.java b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/ForwardingX509Certificate.java new file mode 100644 index 00000000000..19f3616879f --- /dev/null +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/ForwardingX509Certificate.java @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.auth.internal; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Simple forwarding X509Cerficate class. Overrides all abstract and non-abtract methods. + */ +public abstract class ForwardingX509Certificate extends X509Certificate { + + protected abstract X509Certificate delegate(); + + // BEGIN OVERRIDE non-abstract method from X509Certificate.class + + @Override + public X500Principal getIssuerX500Principal() { + return delegate().getIssuerX500Principal(); + } + + @Override + public X500Principal getSubjectX500Principal() { + return delegate().getSubjectX500Principal(); + } + + @Override + public List getExtendedKeyUsage() throws CertificateParsingException { + return delegate().getExtendedKeyUsage(); + } + + @Override + public Collection> getSubjectAlternativeNames() throws CertificateParsingException { + return delegate().getSubjectAlternativeNames(); + } + + @Override + public Collection> getIssuerAlternativeNames() throws CertificateParsingException { + return delegate().getIssuerAlternativeNames(); + } + + // END OVERRIDE non-abstract method from X509Certificate.class + + // BEGIN OVERRIDE non-abstract method from Certificate.class + + @Override + public boolean equals(Object other) { + return delegate().equals(other); + } + + @Override + public int hashCode() { + return delegate().hashCode(); + } + + // END OVERRIDE non-abstract method from Certificate.class + + // everything else below are abstract methods + + @Override + public boolean hasUnsupportedCriticalExtension() { + return delegate().hasUnsupportedCriticalExtension(); + } + + @Override + public Set getCriticalExtensionOIDs() { + return delegate().getCriticalExtensionOIDs(); + } + + @Override + public Set getNonCriticalExtensionOIDs() { + return delegate().getNonCriticalExtensionOIDs(); + } + + @Override + public byte[] getExtensionValue(String oid) { + return delegate().getExtensionValue(oid); + } + + @Override + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException { + delegate().checkValidity(); + } + + @Override + public void checkValidity(Date date) + throws CertificateExpiredException, CertificateNotYetValidException { + delegate().checkValidity(date); + } + + @Override + public int getVersion() { + return delegate().getVersion(); + } + + @Override + public BigInteger getSerialNumber() { + return delegate().getSerialNumber(); + } + + @Override + public Principal getIssuerDN() { + return delegate().getIssuerDN(); + } + + @Override + public Principal getSubjectDN() { + return delegate().getSubjectDN(); + } + + @Override + public Date getNotBefore() { + return delegate().getNotBefore(); + } + + @Override + public Date getNotAfter() { + return delegate().getNotAfter(); + } + + @Override + public byte[] getTBSCertificate() throws CertificateEncodingException { + return delegate().getTBSCertificate(); + } + + @Override + public byte[] getSignature() { + return delegate().getSignature(); + } + + @Override + public String getSigAlgName() { + return delegate().getSigAlgName(); + } + + @Override + public String getSigAlgOID() { + return delegate().getSigAlgOID(); + } + + @Override + public byte[] getSigAlgParams() { + return delegate().getSigAlgParams(); + } + + @Override + public boolean[] getIssuerUniqueID() { + return delegate().getIssuerUniqueID(); + } + + @Override + public boolean[] getSubjectUniqueID() { + return delegate().getSubjectUniqueID(); + } + + @Override + public boolean[] getKeyUsage() { + return delegate().getKeyUsage(); + } + + @Override + public int getBasicConstraints() { + return delegate().getBasicConstraints(); + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + return delegate().getEncoded(); + } + + @Override + public void verify(PublicKey key) + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { + delegate().verify(key); + } + + @Override + public void verify(PublicKey key, String sigProvider) + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { + delegate().verify(key, sigProvider); + } + + @Override + public String toString() { + return delegate().toString(); + } + + @Override + public PublicKey getPublicKey() { + return delegate().getPublicKey(); + } +} diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509CertificateWithOriginalPem.java b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509CertificateWithOriginalPem.java new file mode 100644 index 00000000000..7d721012e6c --- /dev/null +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509CertificateWithOriginalPem.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.auth.internal; + +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * X509CertificateWithOriginalPem is specifically used so that we can keep track of + * the original PEM encoded certificate, along with the parsed X509Certificate that + * it creates. + *

+ * When BouncyCastle (standard or FIPs) is installed as a security provider, and is placed + * first in the list of security providers, the way it parses the PEM file into a X509Certificate + * causes the ordering of OU entries to be modified. When {@link Certificate#getEncoded()} is called, + * the encoded form no longer matches the original value that is in the PEM file. + *

+ * When using Instance Principals, we need to send back the original encoded form of the X509, along with + * it's fingerprint, so that Identity can verify it. If BouncyCastle is used, though, the certificate + * will look tampered with because the encoded form doesn't match what Identity expects. For this case + * specifically, we will attempt to get the encoded bytes from the original PEM file instead and pass + * them back as is, without parsing it to a X509Certificate. + */ +@RequiredArgsConstructor +public class X509CertificateWithOriginalPem extends ForwardingX509Certificate { + private final X509Certificate delegate; + /** + * The original PEM encoded X509. + */ + @Getter private final String pemEncodedCertificate; + + @Override + protected X509Certificate delegate() { + return delegate; + } +} diff --git a/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509FederationClient.java b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509FederationClient.java index 9bde4d12771..dc13016a80f 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509FederationClient.java +++ b/bmc-common/src/main/java/com/oracle/bmc/auth/internal/X509FederationClient.java @@ -183,20 +183,6 @@ private String refreshAndGetSecurityTokenInner(final boolean doFinalTokenValidit } } - private static List removeHostHeader(List headers) { - List copy = new ArrayList<>(); - for (String header : headers) { - if (!header.equals(Constants.HOST)) { - copy.add(header); - } - } - return copy; - } - - private static String keyIdForX509Request(String tenantId, X509Certificate certificate) { - return String.format("%s/fed-x509/%s", tenantId, AuthUtils.getFingerPrint(certificate)); - } - /** * Gets a security token from the federation server * @return the security token, which is basically a JWT token string diff --git a/bmc-common/src/main/java/com/oracle/bmc/http/internal/ResponseHelper.java b/bmc-common/src/main/java/com/oracle/bmc/http/internal/ResponseHelper.java index 9b77f9e6219..0d9098770ca 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/http/internal/ResponseHelper.java +++ b/bmc-common/src/main/java/com/oracle/bmc/http/internal/ResponseHelper.java @@ -3,12 +3,15 @@ */ package com.oracle.bmc.http.internal; +import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.ws.rs.ProcessingException; import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @@ -175,23 +178,35 @@ public static T readEntity(@NonNull final Response response, Class entity // handle the response synchronized (response) { if (response.getStatusInfo().getFamily().equals(Status.Family.SUCCESSFUL)) { - if (entityType != InputStream.class) { - // buffer entity so it can be reread during client parsing (ex, async requests reading - // through both an AsyncHandler and through the returned Future) - // NOTE: do not buffer InputStreams (namely object storage) as those might be very large - response.bufferEntity(); + if (entityType == InputStream.class) { + // If we want an InputStream, then we don't care about the content type. + // This will also allow us to process invalid content types like "text" (instead of "text/plain"). + List contentType = + response.getHeaders().remove(HttpHeaders.CONTENT_TYPE); + LOG.debug( + "Entity type is InputStream, ignoring contentType {} and processing as stream", + contentType); + try { + // NOTE: do not buffer InputStreams (namely object storage) as those might be very large + return response.readEntity(entityType); + } finally { + response.getHeaders().addAll(HttpHeaders.CONTENT_TYPE, contentType); + } } + // buffer entity so it can be reread during client parsing (ex, async requests reading + // through both an AsyncHandler and through the returned Future) + response.bufferEntity(); + T entity = response.readEntity(entityType); - if (MediaType.APPLICATION_JSON_TYPE.equals(response.getMediaType())) { + if (MediaType.APPLICATION_JSON_TYPE.equals(response.getMediaType()) + && entityType == String.class) { // HACK alert, if the entry is a string, and it's mime was // application/json, jackson's provider won't deserialize it since - // the default provider takes presidence. Need to explicitly remove + // the default provider takes precedence. Need to explicitly remove // outer quotes. // TODO: figure out how to do this through providers - if (entityType == String.class) { - return (T) ((String) entity).replaceAll("\"", ""); - } + return (T) ((String) entity).replaceAll("\"", ""); } return entity; } diff --git a/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/BouncyCastleHelper.java b/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/BouncyCastleHelper.java index a42024ba4a1..43b8a438217 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/BouncyCastleHelper.java +++ b/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/BouncyCastleHelper.java @@ -3,7 +3,6 @@ */ package com.oracle.bmc.http.signing.internal; -import com.google.common.base.Throwables; import lombok.extern.slf4j.Slf4j; import java.security.Provider; @@ -18,11 +17,11 @@ private BouncyCastleHelper() { isProviderInstalled = Security.getProvider("BC") != null || Security.getProvider("BCFIPS") != null; try { - final Class bouncyCastleProviderClass = getBouncyCastleProviderClass(); + final Class bouncyCastleProviderClass = getBouncyCastleProviderClass(); bouncyCastleProvider = (Provider) bouncyCastleProviderClass.newInstance(); LOG.info("Instantiated provider: " + bouncyCastleProviderClass.getName()); } catch (InstantiationException | IllegalAccessException ex) { - LOG.error("Failed to instantiate provider", ex); + LOG.error("Failed to instantiate any BouncyCastle provider", ex); throw new BouncyCastleHelperException(ex); } } @@ -43,7 +42,7 @@ Provider getBouncyCastleProvider() { return bouncyCastleProvider; } - private static Class getBouncyCastleProviderClass() { + private static Class getBouncyCastleProviderClass() { LOG.debug("Trying to get BouncyCastleProvider"); try { return Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider"); diff --git a/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplier.java b/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplier.java index 6055d04a7da..6a80d8f039c 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplier.java +++ b/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplier.java @@ -24,7 +24,6 @@ import com.google.common.base.Charsets; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.base.Throwables; import com.oracle.bmc.util.StreamUtils; import lombok.extern.slf4j.Slf4j; diff --git a/bmc-common/src/main/java/com/oracle/bmc/internal/DefaultEndpointConfiguration.java b/bmc-common/src/main/java/com/oracle/bmc/internal/DefaultEndpointConfiguration.java new file mode 100644 index 00000000000..1e410cdb785 --- /dev/null +++ b/bmc-common/src/main/java/com/oracle/bmc/internal/DefaultEndpointConfiguration.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.internal; + +import lombok.AccessLevel; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +/** + * DefaultEndpointConfiguration provides a way to construct the host endpoint for a service + * given a template and some variables based on the default Oracle Cloud Infrastructure naming + * convention. + *

+ * The available variables are: + * - {serviceEndpointPrefix} : The service prefix in the URL. + * - {region} : The public region id, ex, "us-phoenix-1". + * - {secondLevelDomain} : The second level domain associated with the Realm. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class DefaultEndpointConfiguration { + private static final String SERVICE_ENDPOINT_PREFIX_TEMPLATE = "{serviceEndpointPrefix}"; + private static final String REGION_ID_TEMPLATE = + "{region}"; // not regionId for backwards compatibility + private static final String SECOND_LEVEL_DOMAIN_TEMPLATE = "{secondLevelDomain}"; + + // the endpoint template that will be used. + private final String endpointTemplate; + + private String serviceEndpointPrefix; + private String regionId; + private String secondLevelDomain; + + /** + * Creates a new builder starting with the given template. + * @param endpointTemplate The template + * @return A new builder. + */ + public static DefaultEndpointConfiguration builder(@NonNull String endpointTemplate) { + return new DefaultEndpointConfiguration(endpointTemplate); + } + + /** + * Sets the service endpoint prefix, if one. + * + * @param serviceEndpointPrefix The service endpoint prefix. + * @return This builder + */ + public DefaultEndpointConfiguration serviceEndpointPrefix(String serviceEndpointPrefix) { + this.serviceEndpointPrefix = serviceEndpointPrefix; + return this; + } + + /** + * Sets the regionId, if one. + * + * @param regionId The region id. + * @return This builder + */ + public DefaultEndpointConfiguration regionId(String regionId) { + this.regionId = regionId; + return this; + } + + /** + * Sets the second level domain, if one. + * + * @param secondLevelDomain The second level domain of the Realm. + * @return This builder + */ + public DefaultEndpointConfiguration secondLevelDomain(String secondLevelDomain) { + this.secondLevelDomain = secondLevelDomain; + return this; + } + + /** + * Builds the final endpoint based on the variables provided. + * @return The endpoint. + */ + public String build() { + String endpoint = endpointTemplate; + if (serviceEndpointPrefix != null) { + endpoint = endpoint.replace(SERVICE_ENDPOINT_PREFIX_TEMPLATE, serviceEndpointPrefix); + } + if (regionId != null) { + endpoint = endpoint.replace(REGION_ID_TEMPLATE, regionId); + } + if (secondLevelDomain != null) { + endpoint = endpoint.replace(SECOND_LEVEL_DOMAIN_TEMPLATE, secondLevelDomain); + } + return endpoint; + } +} diff --git a/bmc-common/src/main/java/com/oracle/bmc/internal/EndpointBuilder.java b/bmc-common/src/main/java/com/oracle/bmc/internal/EndpointBuilder.java new file mode 100644 index 00000000000..b3ac07ab8a9 --- /dev/null +++ b/bmc-common/src/main/java/com/oracle/bmc/internal/EndpointBuilder.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.internal; + +import org.apache.commons.lang3.StringUtils; + +import com.google.common.collect.ImmutableMap; +import com.oracle.bmc.Realm; +import com.oracle.bmc.Region; +import com.oracle.bmc.Service; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * EndpointBuilder provides a wrapper to construct the appropriate + * endpoint for a service. The service may override the endpoint template, but + * if not, a default template will be used. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class EndpointBuilder { + public static final String DEFAULT_ENDPOINT_TEMPLATE = + "https://{serviceEndpointPrefix}.{region}.{secondLevelDomain}"; + + @RequiredArgsConstructor + private enum SecondLevelDomainNames { + ORACLECLOUD_COM("oraclecloud.com"); + + /** + * The default second level domain for all regions in this realm. + * Does not start with '.'. + */ + private final String secondLevelDomain; + } + + @Getter(value = AccessLevel.PACKAGE) + private final static ImmutableMap realmToSecondLevelDomainName = + ImmutableMap.of(Realm.OC1, SecondLevelDomainNames.ORACLECLOUD_COM.secondLevelDomain); + + /** + * Creates the service endpoint using the {@link DefaultEndpointConfiguration} + * method. + * + * @param service The service + * @param regionId The regionId + * @param realm The realm this region belongs to. + * @return The endpoint (protocol + FQDN) for this service. + */ + public static String createEndpoint(Service service, String regionId, Realm realm) { + final String endpointTemplateToUse; + if (StringUtils.isNotBlank(service.getServiceEndpointTemplate())) { + endpointTemplateToUse = service.getServiceEndpointTemplate(); + } else { + endpointTemplateToUse = DEFAULT_ENDPOINT_TEMPLATE; + } + + return DefaultEndpointConfiguration.builder(endpointTemplateToUse) + .regionId(regionId) + .serviceEndpointPrefix(service.getServiceEndpointPrefix()) + .secondLevelDomain(realmToSecondLevelDomainName.get(realm)) + .build(); + } + + /** + * Creates the service endpoint using the {@link DefaultEndpointConfiguration} + * method. + * + * @param service The service + * @param region The region + * @return The endpoint (protocol + FQDN) for this service. + */ + public static String createEndpoint(Service service, Region region) { + return createEndpoint(service, region.getRegionId(), region.getRealm()); + } +} diff --git a/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/AbstractResponseIterator.java b/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/AbstractResponseIterator.java index 15a465c2124..07da49a6e91 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/AbstractResponseIterator.java +++ b/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/AbstractResponseIterator.java @@ -83,7 +83,7 @@ public AbstractResponseIterator( */ protected REQUEST getNextRequest() { final RequestBuilderAndToken requestBuilderAndToken = - new RequestBuilderAndToken(requestBuilder, getNextPageToken()); + new RequestBuilderAndToken<>(requestBuilder, getNextPageToken()); return requestBuilderFunction.apply(requestBuilderAndToken); } diff --git a/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseIterator.java b/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseIterator.java index 5a4c2c32d99..09d1d597aa4 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseIterator.java +++ b/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseIterator.java @@ -24,8 +24,6 @@ public class ResponseIterator extends AbstractResponseIterator implements Iterator { - private boolean anyFetchPerformed; - /** * Constructs a new ResponseIterator. * diff --git a/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseRecordIterator.java b/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseRecordIterator.java index 67346928f3a..d4031eb266d 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseRecordIterator.java +++ b/bmc-common/src/main/java/com/oracle/bmc/paginator/internal/ResponseRecordIterator.java @@ -119,7 +119,7 @@ public void remove() { private void getFirstPage() { final RequestBuilderAndToken requestBuilderAndToken = - new RequestBuilderAndToken(requestBuilder, null); + new RequestBuilderAndToken<>(requestBuilder, null); currentResponse = pageRetrievalFunction.apply(requestBuilderFunction.apply(requestBuilderAndToken)); diff --git a/bmc-common/src/main/resources/com/oracle/bmc/sdk.properties b/bmc-common/src/main/resources/com/oracle/bmc/sdk.properties index 349fa0e2ec4..902fe486602 100644 --- a/bmc-common/src/main/resources/com/oracle/bmc/sdk.properties +++ b/bmc-common/src/main/resources/com/oracle/bmc/sdk.properties @@ -1,2 +1 @@ -sdk.version = ${pom.version} -endpoint.defaultFormat=https://%s.%s.oraclecloud.com \ No newline at end of file +sdk.version = ${pom.version} \ No newline at end of file diff --git a/bmc-common/src/test/java/com/oracle/bmc/RealmTest.java b/bmc-common/src/test/java/com/oracle/bmc/RealmTest.java new file mode 100644 index 00000000000..88d085fc478 --- /dev/null +++ b/bmc-common/src/test/java/com/oracle/bmc/RealmTest.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc; + +import static org.junit.Assert.assertFalse; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +public class RealmTest { + @Test + public void noDuplicateRealmId() { + Set realmIds = new HashSet<>(); + for (Realm realm : Realm.values()) { + assertFalse(realmIds.contains(realm.getRealmId())); + realmIds.add(realm.getRealmId()); + } + } +} diff --git a/bmc-common/src/test/java/com/oracle/bmc/RegionTest.java b/bmc-common/src/test/java/com/oracle/bmc/RegionTest.java index f7bed711103..faa6ea960ba 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/RegionTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/RegionTest.java @@ -9,17 +9,62 @@ import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertFalse; + +import java.util.HashSet; +import java.util.Set; public class RegionTest { + + private static final Service TEST_SERVICE = + Services.serviceBuilder() + .serviceEndpointPrefix("foobar") + .serviceName("RegionTest") + .build(); + @Test public void validRegion() { - assertEquals(Region.US_PHOENIX_1, Region.fromRegionCodeOrId("phx")); + for (Region region : Region.values()) { + assertEquals(region, Region.fromRegionId(region.getRegionId())); + assertEquals(region, Region.fromRegionCode(region.getRegionCode())); + assertEquals(region, Region.fromRegionCodeOrId(region.getRegionId())); + assertEquals(region, Region.fromRegionCodeOrId(region.getRegionCode())); + } + } - assertEquals(Region.US_ASHBURN_1, Region.fromRegionCodeOrId("iad")); - assertEquals(Region.EU_FRANKFURT_1, Region.fromRegionCodeOrId("fra")); - assertEquals(Region.EU_FRANKFURT_1, Region.fromRegionCodeOrId("eu-frankfurt-1")); - assertEquals(Region.UK_LONDON_1, Region.fromRegionCodeOrId("lhr")); - assertEquals(Region.UK_LONDON_1, Region.fromRegionCodeOrId("uk-london-1")); + @Test + public void regionalEndpoint_withRegionEnum_andRegionString_oc1() { + String expectedEndpoint = "https://foobar.us-phoenix-1.oraclecloud.com"; + Region oc1Region = Region.US_PHOENIX_1; + assertEquals(expectedEndpoint, Region.formatDefaultRegionEndpoint(TEST_SERVICE, oc1Region)); + assertEquals( + expectedEndpoint, + Region.formatDefaultRegionEndpoint(TEST_SERVICE, oc1Region.getRegionId())); + } + + @Test + public void regionalEndpoint_withUnknownRegionString_defaultsToOc1() { + assertEquals( + "https://foobar.us-foobar-1.oraclecloud.com", + Region.formatDefaultRegionEndpoint(TEST_SERVICE, "us-foobar-1")); + } + + @Test + public void noDuplicateRegionId() { + Set regionIds = new HashSet<>(); + for (Region region : Region.values()) { + assertFalse(regionIds.contains(region.getRegionId())); + regionIds.add(region.getRegionId()); + } + } + + @Test + public void noDuplicateRegionCode() { + Set regionCodes = new HashSet<>(); + for (Region region : Region.values()) { + assertFalse(regionCodes.contains(region.getRegionCode())); + regionCodes.add(region.getRegionCode()); + } } @Test diff --git a/bmc-common/src/test/java/com/oracle/bmc/ServicesTest.java b/bmc-common/src/test/java/com/oracle/bmc/ServicesTest.java index 94a4c5acc10..41adc79ded4 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/ServicesTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/ServicesTest.java @@ -10,45 +10,40 @@ public class ServicesTest { @BeforeClass public static void setup() { - final Service fooService = - Services.serviceBuilder().serviceName("FOO").serviceEndpointPrefix("foo").build(); + Services.serviceBuilder().serviceName("FOO").serviceEndpointPrefix("foo").build(); } @Test public void addNewService() { - final Service newService = - Services.serviceBuilder().serviceName("NEW").serviceEndpointPrefix("new").build(); + Services.serviceBuilder().serviceName("NEW").serviceEndpointPrefix("new").build(); } @Test - public void addExistingService() { - final Service fooService = - Services.serviceBuilder().serviceName("FOO").serviceEndpointPrefix("foo").build(); + public void addExistingService_sameDefinition() { + Services.serviceBuilder().serviceName("FOO").serviceEndpointPrefix("foo").build(); } @Test(expected = IllegalArgumentException.class) - public void addExistingService_ConflictingEndpointPrefix() { - final Service fooService = - Services.serviceBuilder().serviceName("FOO").serviceEndpointPrefix("bar").build(); + public void addExistingService_conflictingEndpointPrefix() { + Services.serviceBuilder().serviceName("FOO").serviceEndpointPrefix("bar").build(); } @Test(expected = IllegalArgumentException.class) - public void addExistingService_ConflictingEndpointTemplate() { - final Service fooService = - Services.serviceBuilder() - .serviceName("FOO") - .serviceEndpointPrefix("foo") - .serviceEndpointTemplate("{region}.foo.oci.oraclecloud.com") - .build(); + public void addExistingService_conflictingEndpointTemplate() { + Services.serviceBuilder() + .serviceName("FOO") + .serviceEndpointPrefix("foo") + .serviceEndpointTemplate("{region}.foo.oci.oraclecloud.com") + .build(); } @Test(expected = NullPointerException.class) - public void addService_NoName() { - final Service noNameService = Services.serviceBuilder().build(); + public void addService_noName() { + Services.serviceBuilder().build(); } @Test(expected = IllegalArgumentException.class) - public void addService_BlankName() { - final Service blankNameService = Services.serviceBuilder().serviceName("").build(); + public void addService_blankServiceName() { + Services.serviceBuilder().serviceName("").build(); } } diff --git a/bmc-common/src/test/java/com/oracle/bmc/http/internal/ExplicitlySetFilterTest.java b/bmc-common/src/test/java/com/oracle/bmc/http/internal/ExplicitlySetFilterTest.java index 3d3f518f771..a33fe9cd7b0 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/http/internal/ExplicitlySetFilterTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/http/internal/ExplicitlySetFilterTest.java @@ -118,18 +118,30 @@ public void testNullInSubclass() throws Exception { @Test public void deserializeNoDiscriminator() throws IOException { Subclass sub = Subclass.builder().baseVal(1).subVal("two").build(); - String serialized = serializeForPost(sub); - - assertTrue(serialized.contains("\"type\":\"sub\"")); - String replaced = serialized.replace("sub", "unknown"); - assertTrue(replaced.contains("\"type\":\"unknown\"")); - - Baseclass parsedSub = - RestClientFactory.getObjectMapper().readValue(serialized, Baseclass.class); - assertEquals(Subclass.class, parsedSub.getClass()); - Baseclass parsedUnknown = - RestClientFactory.getObjectMapper().readValue(replaced, Baseclass.class); - assertEquals(Baseclass.class, parsedUnknown.getClass()); + + Client client = mock(Client.class); + EntityFactory ef = mock(EntityFactory.class); + try (RestClient rc = new RestClient(client, ef)) { + Invocation.Builder ib = mock(Invocation.Builder.class); + rc.post(new WrappedInvocationBuilder(ib), sub, new BmcRequest()); + + ArgumentCaptor bodyCaptor = ArgumentCaptor.forClass(Object.class); + verify(ef).forPost(any(), bodyCaptor.capture()); + + Object value = bodyCaptor.getValue(); + + String serialized = value.toString(); + assertTrue(serialized.contains("\"type\":\"sub\"")); + String replaced = serialized.replace("sub", "unknown"); + assertTrue(replaced.contains("\"type\":\"unknown\"")); + + Baseclass parsedSub = + RestClientFactory.getObjectMapper().readValue(serialized, Baseclass.class); + assertEquals(Subclass.class, parsedSub.getClass()); + Baseclass parsedUnknown = + RestClientFactory.getObjectMapper().readValue(replaced, Baseclass.class); + assertEquals(Baseclass.class, parsedUnknown.getClass()); + } } @Test diff --git a/bmc-common/src/test/java/com/oracle/bmc/http/internal/ResponseHelperTest.java b/bmc-common/src/test/java/com/oracle/bmc/http/internal/ResponseHelperTest.java index 9a42a9ffab5..43ba0a0120d 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/http/internal/ResponseHelperTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/http/internal/ResponseHelperTest.java @@ -3,16 +3,27 @@ */ package com.oracle.bmc.http.internal; +import com.google.common.collect.ImmutableList; import com.oracle.bmc.model.BmcException; import org.junit.Test; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; +import java.io.InputStream; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; public class ResponseHelperTest { @@ -68,6 +79,35 @@ public void test_throwIfNotSuccessful_InvalidJsonResponse() { } } + @Test + public void testReadEntity_streamWithConentType() { + Response response = mock(Response.class); + Response.StatusType statusInfo = mock(Response.StatusType.class); + MultivaluedMap headers = mock(MultivaluedMap.class); + List contentType = ImmutableList.of("text"); + InputStream mockStream = mock(InputStream.class); + + Class entityType = InputStream.class; + + when(response.getStatusInfo()).thenReturn(statusInfo); + when(statusInfo.getFamily()).thenReturn(Response.Status.Family.SUCCESSFUL); + when(response.getHeaders()).thenReturn(headers); + when(headers.remove(HttpHeaders.CONTENT_TYPE)).thenReturn(contentType); + when(response.readEntity(entityType)).thenReturn(mockStream); + + InputStream inputStream = (InputStream) ResponseHelper.readEntity(response, entityType); + + assertTrue(inputStream == mockStream); + verify(response).getStatusInfo(); + verify(statusInfo).getFamily(); + verify(response, atLeastOnce()).getHeaders(); + verify(headers).remove(HttpHeaders.CONTENT_TYPE); + verify(response).readEntity(entityType); + verify(headers).addAll(HttpHeaders.CONTENT_TYPE, contentType); + verify(response, never()).bufferEntity(); + verifyNoMoreInteractions(response, statusInfo, headers, mockStream); + } + private static Response buildMockResponse( final String opcRequestId, final MediaType mediaType, final Response.Status status) { final Response response = mock(Response.class); diff --git a/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplierTest.java b/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplierTest.java index 5696236793a..05c970faeb6 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplierTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/PEMFileRSAPrivateKeySupplierTest.java @@ -8,8 +8,6 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import static org.junit.Assert.fail; diff --git a/bmc-common/src/test/java/com/oracle/bmc/internal/DefaultEndpointConfigurationTest.java b/bmc-common/src/test/java/com/oracle/bmc/internal/DefaultEndpointConfigurationTest.java new file mode 100644 index 00000000000..a44e9f11a62 --- /dev/null +++ b/bmc-common/src/test/java/com/oracle/bmc/internal/DefaultEndpointConfigurationTest.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.internal; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class DefaultEndpointConfigurationTest { + + @Test + public void allVariables_allFilledIn() { + String endpoint = + DefaultEndpointConfiguration.builder( + "https://{serviceEndpointPrefix}.{region}.{secondLevelDomain}") + .secondLevelDomain("oraclecloud.com") + .serviceEndpointPrefix("objectstorage") + .regionId("us-phoenix-1") + .build(); + assertEquals("https://objectstorage.us-phoenix-1.oraclecloud.com", endpoint); + } + + @Test + public void allVariables_noneFilledIn() { + String endpoint = + DefaultEndpointConfiguration.builder( + "https://{serviceEndpointPrefix}.{region}.{secondLevelDomain}") + .build(); + assertEquals("https://{serviceEndpointPrefix}.{region}.{secondLevelDomain}", endpoint); + } + + @Test + public void someVariables_noSecondLevelDomain() { + String endpoint = + DefaultEndpointConfiguration.builder( + "https://{serviceEndpointPrefix}.{region}.oracle.com") + .secondLevelDomain("oraclecloud.com") + .serviceEndpointPrefix("objectstorage") + .regionId("us-phoenix-1") + .build(); + assertEquals("https://objectstorage.us-phoenix-1.oracle.com", endpoint); + } + + @Test + public void someVariables_noServiceName_noSecondLevelDomain() { + String endpoint = + DefaultEndpointConfiguration.builder("https://foobar.{region}.oci.oracle.com") + .secondLevelDomain("oraclecloud.com") + .serviceEndpointPrefix("objectstorage") + .regionId("us-phoenix-1") + .build(); + assertEquals("https://foobar.us-phoenix-1.oci.oracle.com", endpoint); + } +} diff --git a/bmc-common/src/test/java/com/oracle/bmc/internal/EndpointBuilderTest.java b/bmc-common/src/test/java/com/oracle/bmc/internal/EndpointBuilderTest.java new file mode 100644 index 00000000000..6f076683efe --- /dev/null +++ b/bmc-common/src/test/java/com/oracle/bmc/internal/EndpointBuilderTest.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.internal; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import com.oracle.bmc.Realm; +import com.oracle.bmc.Region; +import com.oracle.bmc.Service; +import com.oracle.bmc.Services; + +public class EndpointBuilderTest { + + @Test + public void allRealmsHaveSecondLevelDomainsConfigured() { + for (Realm realm : Realm.values()) { + assertNotNull(EndpointBuilder.getRealmToSecondLevelDomainName().get(realm)); + } + } + + @Test + public void createEndpoint_useDefaultTemplate() { + Service testService = + Services.serviceBuilder() + .serviceEndpointPrefix("foobar") + .serviceName("EndpointBuilderTest1") + .build(); + assertEquals( + "https://foobar.us-phoenix-1.oraclecloud.com", + EndpointBuilder.createEndpoint(testService, Region.US_PHOENIX_1)); + } + + @Test + public void createEndpoint_useCustomTemplate() { + Service testService = + Services.serviceBuilder() + .serviceEndpointPrefix("foobar") + .serviceName("EndpointBuilderTest2") + .serviceEndpointTemplate("https://foobar2.{region}.oracle.com") + .build(); + assertEquals( + "https://foobar2.us-phoenix-1.oracle.com", + EndpointBuilder.createEndpoint(testService, Region.US_PHOENIX_1)); + } + + @Test + public void createEndpoint_useCustomTemplate_allTemplatesUsed() { + Service testService = + Services.serviceBuilder() + .serviceEndpointPrefix("foobar") + .serviceName("EndpointBuilderTest3") + .serviceEndpointTemplate( + "http://{serviceEndpointPrefix}.{region}.{secondLevelDomain}") + .build(); + assertEquals( + "http://foobar.us-phoenix-1.oraclecloud.com", + EndpointBuilder.createEndpoint(testService, Region.US_PHOENIX_1)); + } +} diff --git a/bmc-common/src/test/java/com/oracle/bmc/util/internal/HttpUtilsTest.java b/bmc-common/src/test/java/com/oracle/bmc/util/internal/HttpUtilsTest.java index 1e8d5b4538d..95f44032dba 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/util/internal/HttpUtilsTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/util/internal/HttpUtilsTest.java @@ -17,6 +17,7 @@ import java.util.UUID; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -97,6 +98,7 @@ public void encodeMapQueryParam_mapOfStringToBoolean() { WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeMapQueryParam(wrapped, prefix, definedTagsExists); + assertNotNull(result); String prefixEncoded = "definedTags%20Exists."; String keyName2Encoded = "tagMust%20NotExist"; @@ -127,6 +129,7 @@ public void attemptEncodeQueryParam_mapOfStringToListOfString() WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeMapQueryParam(wrapped, prefix, definedTags); + assertNotNull(result); String prefixEncoded = "defined%20Tags."; String keyName2Encoded = "tag%202"; @@ -164,6 +167,7 @@ public void encodeMapQueryParam_mapOfStringToBoolean_nullPrefix() { WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeMapQueryParam(wrapped, prefix, definedTagsExists); + assertNotNull(result); String prefixEncoded = ""; String keyName2Encoded = "tagMust%20NotExist"; @@ -226,6 +230,7 @@ public void encodeCollectionFormatQueryParam_singleElementList() { WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeCollectionFormatQueryParam(wrapped, "unitTest", values, cft); + assertNotNull(result); verify(target).queryParam("unitTest", "single"); } @@ -243,6 +248,7 @@ public void encodeCollectionFormatQueryParam_multipleElementList() { WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeCollectionFormatQueryParam(wrapped, "unitTest", values, cft); + assertNotNull(result); if (cft == CollectionFormatType.CommaSeparated) { verify(target).queryParam("unitTest", "number1,number2"); @@ -272,6 +278,7 @@ public void encodeCollectionFormatQueryParam_enumListMembers() { WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeCollectionFormatQueryParam(wrapped, "unitTest", values, cft); + assertNotNull(result); if (cft == CollectionFormatType.CommaSeparated) { verify(target).queryParam("unitTest", "PROVISIONING,STOPPING"); @@ -301,6 +308,7 @@ public void encodeCollectionFormatQueryParam_nullMembersIgnored() { WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeCollectionFormatQueryParam(wrapped, "unitTest", values, cft); + assertNotNull(result); if (cft == CollectionFormatType.CommaSeparated) { verify(target).queryParam("unitTest", "RUNNING"); diff --git a/bmc-containerengine/pom.xml b/bmc-containerengine/pom.xml index 5eea79584f7..d79d9dd03c8 100644 --- a/bmc-containerengine/pom.xml +++ b/bmc-containerengine/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-core/pom.xml b/bmc-core/pom.xml index 96d7e810907..1188d4a4af8 100644 --- a/bmc-core/pom.xml +++ b/bmc-core/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-database/pom.xml b/bmc-database/pom.xml index 9d0746b13ee..96348548e2f 100644 --- a/bmc-database/pom.xml +++ b/bmc-database/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-dns/pom.xml b/bmc-dns/pom.xml index b252da55b3c..d3bce4ccee4 100644 --- a/bmc-dns/pom.xml +++ b/bmc-dns/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-email/pom.xml b/bmc-email/pom.xml index 1c249f59903..77c3f10e067 100644 --- a/bmc-email/pom.xml +++ b/bmc-email/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-examples/pom.xml b/bmc-examples/pom.xml index 680b4dbc191..29291b86d73 100644 --- a/bmc-examples/pom.xml +++ b/bmc-examples/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-bom - 1.3.1 + 1.3.2 pom import diff --git a/bmc-examples/src/main/java/ObjectStorageGetBucketExample.java b/bmc-examples/src/main/java/ObjectStorageGetBucketExample.java new file mode 100644 index 00000000000..8ddeb787160 --- /dev/null +++ b/bmc-examples/src/main/java/ObjectStorageGetBucketExample.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +import com.oracle.bmc.Region; +import com.oracle.bmc.auth.AuthenticationDetailsProvider; +import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; +import com.oracle.bmc.objectstorage.ObjectStorage; +import com.oracle.bmc.objectstorage.ObjectStorageClient; +import com.oracle.bmc.objectstorage.model.CreateBucketDetails; +import com.oracle.bmc.objectstorage.requests.CreateBucketRequest; +import com.oracle.bmc.objectstorage.requests.GetBucketRequest; +import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; +import com.oracle.bmc.objectstorage.requests.PutObjectRequest; +import com.oracle.bmc.objectstorage.responses.GetBucketResponse; +import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * Example to get a bucket and its statistics. + *

+ * This example first creates a bucket in the compartment corresponding to the compartment OCID passed as the first + * argument to this program. The name of the bucket created is same as the second argument to the program. It also + * creates an object in this bucket whose name is the third argument. + *

+ * It then illustrates how we can get a bucket and its statistics (Estimated Size and Estimated Count). + * + * + * @param args Arguments to provide to the example. The following arguments are expected: + *
    + *
  • The first argument is the OCID of the compartment.
  • + *
  • The second is the name of bucket to create and later fetch
  • + *
  • The third is the name of object to create inside bucket
  • + *
+ */ +public class ObjectStorageGetBucketExample { + public static void main(String[] args) throws Exception { + String configurationFilePath = "~/.oci/config"; + String profile = "DEFAULT"; + + if (args.length != 3) { + throw new IllegalArgumentException( + "Unexpected number of arguments received. Consult the script header comments for expected arguments"); + } + + final String compartmentId = args[0]; + final String bucket = args[1]; + final String object = args[2]; + + AuthenticationDetailsProvider provider = + new ConfigFileAuthenticationDetailsProvider(configurationFilePath, profile); + + ObjectStorage client = new ObjectStorageClient(provider); + client.setRegion(Region.US_PHOENIX_1); + + System.out.println("Getting the namespace."); + GetNamespaceResponse namespaceResponse = + client.getNamespace(GetNamespaceRequest.builder().build()); + String namespaceName = namespaceResponse.getValue(); + + System.out.println("Creating the source bucket."); + CreateBucketDetails createSourceBucketDetails = + CreateBucketDetails.builder().compartmentId(compartmentId).name(bucket).build(); + CreateBucketRequest createSourceBucketRequest = + CreateBucketRequest.builder() + .namespaceName(namespaceName) + .createBucketDetails(createSourceBucketDetails) + .build(); + client.createBucket(createSourceBucketRequest); + + System.out.println("Creating the source object"); + PutObjectRequest putObjectRequest = + PutObjectRequest.builder() + .namespaceName(namespaceName) + .bucketName(bucket) + .objectName(object) + .contentLength(4L) + .putObjectBody( + new ByteArrayInputStream("data".getBytes(StandardCharsets.UTF_8))) + .build(); + client.putObject(putObjectRequest); + + System.out.println("Creating Get bucket request"); + List fieldsList = new ArrayList<>(2); + fieldsList.add(GetBucketRequest.Fields.ApproximateCount); + fieldsList.add(GetBucketRequest.Fields.ApproximateSize); + GetBucketRequest request = + GetBucketRequest.builder() + .namespaceName(namespaceName) + .bucketName(bucket) + .fields(fieldsList) + .build(); + + System.out.println("Fetching bucket details"); + GetBucketResponse response = client.getBucket(request); + + System.out.println("Bucket Name : " + response.getBucket().getName()); + System.out.println("Bucket Compartment : " + response.getBucket().getCompartmentId()); + System.out.println( + "The Approximate total number of objects within this bucket : " + + response.getBucket().getApproximateCount()); + System.out.println( + "The Approximate total size of objects within this bucket : " + + response.getBucket().getApproximateSize()); + } +} diff --git a/bmc-examples/src/main/java/RawRestCallExample.java b/bmc-examples/src/main/java/RawRestCallExample.java index 8e1aec63e73..5249445ef7c 100644 --- a/bmc-examples/src/main/java/RawRestCallExample.java +++ b/bmc-examples/src/main/java/RawRestCallExample.java @@ -93,8 +93,11 @@ public void filter(@NonNull ClientRequestContext clientRequestContext) throws IO clientRequestContext.getStringHeaders(), clientRequestContext.getEntity()); + final MultivaluedMap headers = clientRequestContext.getHeaders(); for (Map.Entry e : authHeaders.entrySet()) { - clientRequestContext.getHeaders().putSingle(e.getKey(), e.getValue()); + if (!headers.keySet().contains(e.getKey())) { + headers.putSingle(e.getKey(), e.getValue()); + } } } } diff --git a/bmc-filestorage/pom.xml b/bmc-filestorage/pom.xml index 06f34e01de8..5e83314927e 100644 --- a/bmc-filestorage/pom.xml +++ b/bmc-filestorage/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-full/pom.xml b/bmc-full/pom.xml index ec7f7a62c1a..aa05a27e684 100644 --- a/bmc-full/pom.xml +++ b/bmc-full/pom.xml @@ -4,7 +4,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml oci-java-sdk-full @@ -16,7 +16,7 @@ com.oracle.oci.sdk oci-java-sdk-bom - 1.3.1 + 1.3.2 pom import diff --git a/bmc-identity/pom.xml b/bmc-identity/pom.xml index 82789f106a3..8f4780d81fe 100644 --- a/bmc-identity/pom.xml +++ b/bmc-identity/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-keymanagement/pom.xml b/bmc-keymanagement/pom.xml index c1ab789099a..e8b1f090c62 100644 --- a/bmc-keymanagement/pom.xml +++ b/bmc-keymanagement/pom.xml @@ -4,7 +4,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml oci-java-sdk-keymanagement @@ -17,7 +17,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-loadbalancer/pom.xml b/bmc-loadbalancer/pom.xml index 6b6d6c70098..1a081040bde 100644 --- a/bmc-loadbalancer/pom.xml +++ b/bmc-loadbalancer/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-objectstorage/bmc-objectstorage-combined/pom.xml b/bmc-objectstorage/bmc-objectstorage-combined/pom.xml index acb26755334..b32c216cfe2 100644 --- a/bmc-objectstorage/bmc-objectstorage-combined/pom.xml +++ b/bmc-objectstorage/bmc-objectstorage-combined/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk-objectstorage-parent - 1.3.1 + 1.3.2 ../pom.xml @@ -18,12 +18,12 @@ com.oracle.oci.sdk oci-java-sdk-objectstorage-generated - 1.3.1 + 1.3.2 com.oracle.oci.sdk oci-java-sdk-objectstorage-extensions - 1.3.1 + 1.3.2 diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/pom.xml b/bmc-objectstorage/bmc-objectstorage-extensions/pom.xml index 8315c0e6264..cc528274b1b 100644 --- a/bmc-objectstorage/bmc-objectstorage-extensions/pom.xml +++ b/bmc-objectstorage/bmc-objectstorage-extensions/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk-objectstorage-parent - 1.3.1 + 1.3.2 ../pom.xml @@ -19,12 +19,12 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 com.oracle.oci.sdk oci-java-sdk-objectstorage-generated - 1.3.1 + 1.3.2 diff --git a/bmc-objectstorage/bmc-objectstorage-generated/pom.xml b/bmc-objectstorage/bmc-objectstorage-generated/pom.xml index 0aea05368ec..3a4d0f3980e 100644 --- a/bmc-objectstorage/bmc-objectstorage-generated/pom.xml +++ b/bmc-objectstorage/bmc-objectstorage-generated/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk-objectstorage-parent - 1.3.1 + 1.3.2 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/internal/http/GetBucketConverter.java b/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/internal/http/GetBucketConverter.java index daff2662f33..174f0e67092 100644 --- a/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/internal/http/GetBucketConverter.java +++ b/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/internal/http/GetBucketConverter.java @@ -38,6 +38,15 @@ public static com.oracle.bmc.http.internal.WrappedInvocationBuilder fromRequest( com.oracle.bmc.util.internal.HttpUtils.encodePathSegment( request.getBucketName())); + if (request.getFields() != null) { + target = + com.oracle.bmc.util.internal.HttpUtils.encodeCollectionFormatQueryParam( + target, + "fields", + request.getFields(), + com.oracle.bmc.util.internal.CollectionFormatType.CommaSeparated); + } + com.oracle.bmc.http.internal.WrappedInvocationBuilder ib = target.request(); ib.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON); diff --git a/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/model/Bucket.java b/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/model/Bucket.java index 2145f14b9cd..67dc18fb6bb 100644 --- a/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/model/Bucket.java +++ b/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/model/Bucket.java @@ -147,6 +147,24 @@ public Builder objectLifecyclePolicyEtag(String objectLifecyclePolicyEtag) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("approximateCount") + private Long approximateCount; + + public Builder approximateCount(Long approximateCount) { + this.approximateCount = approximateCount; + this.__explicitlySet__.add("approximateCount"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonProperty("approximateSize") + private Long approximateSize; + + public Builder approximateSize(Long approximateSize) { + this.approximateSize = approximateSize; + this.__explicitlySet__.add("approximateSize"); + return this; + } + @com.fasterxml.jackson.annotation.JsonIgnore private final java.util.Set __explicitlySet__ = new java.util.HashSet(); @@ -165,7 +183,9 @@ public Bucket build() { freeformTags, definedTags, kmsKeyId, - objectLifecyclePolicyEtag); + objectLifecyclePolicyEtag, + approximateCount, + approximateSize); __instance__.__explicitlySet__.addAll(__explicitlySet__); return __instance__; } @@ -185,7 +205,9 @@ public Builder copy(Bucket o) { .freeformTags(o.getFreeformTags()) .definedTags(o.getDefinedTags()) .kmsKeyId(o.getKmsKeyId()) - .objectLifecyclePolicyEtag(o.getObjectLifecyclePolicyEtag()); + .objectLifecyclePolicyEtag(o.getObjectLifecyclePolicyEtag()) + .approximateCount(o.getApproximateCount()) + .approximateSize(o.getApproximateSize()); copiedBuilder.__explicitlySet__.retainAll(o.__explicitlySet__); return copiedBuilder; @@ -394,6 +416,22 @@ public static StorageTier create(String key) { @com.fasterxml.jackson.annotation.JsonProperty("objectLifecyclePolicyEtag") String objectLifecyclePolicyEtag; + /** + * The approximate number of objects in the bucket. Count statistics are reported periodically. You will see a + * lag between what is displayed and the actual object count. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("approximateCount") + Long approximateCount; + + /** + * The approximate total size of all objects in the bucket. Size statistics are reported periodically. You will + * see a lag between what is displayed and the actual size of the bucket. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("approximateSize") + Long approximateSize; + @com.fasterxml.jackson.annotation.JsonIgnore private final java.util.Set __explicitlySet__ = new java.util.HashSet(); } diff --git a/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/requests/GetBucketRequest.java b/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/requests/GetBucketRequest.java index 0dad33d6b51..94aa22a3b05 100644 --- a/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/requests/GetBucketRequest.java +++ b/bmc-objectstorage/bmc-objectstorage-generated/src/main/java/com/oracle/bmc/objectstorage/requests/GetBucketRequest.java @@ -41,6 +41,53 @@ public class GetBucketRequest extends com.oracle.bmc.requests.BmcRequest { */ private String opcClientRequestId; + /** + * Bucket summary includes the 'namespace', 'name', 'compartmentId', 'createdBy', 'timeCreated', + * and 'etag' fields. This parameter can also include 'approximateCount' (Approximate number of objects) and 'approximateSize' + * (total approximate size in bytes of all objects). For example 'approximateCount,approximateSize' + * + */ + private java.util.List fields; + + /** + * Bucket summary includes the 'namespace', 'name', 'compartmentId', 'createdBy', 'timeCreated', + * and 'etag' fields. This parameter can also include 'approximateCount' (Approximate number of objects) and 'approximateSize' + * (total approximate size in bytes of all objects). For example 'approximateCount,approximateSize' + * + **/ + public enum Fields { + ApproximateCount("approximateCount"), + ApproximateSize("approximateSize"), + ; + + private final String value; + private static java.util.Map map; + + static { + map = new java.util.HashMap<>(); + for (Fields v : Fields.values()) { + map.put(v.getValue(), v); + } + } + + Fields(String value) { + this.value = value; + } + + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { + return value; + } + + @com.fasterxml.jackson.annotation.JsonCreator + public static Fields create(String key) { + if (map.containsKey(key)) { + return map.get(key); + } + throw new RuntimeException("Invalid Fields: " + key); + } + }; + public static class Builder { private com.oracle.bmc.util.internal.Consumer invocationCallback = null; @@ -67,6 +114,7 @@ public Builder copy(GetBucketRequest o) { ifMatch(o.getIfMatch()); ifNoneMatch(o.getIfNoneMatch()); opcClientRequestId(o.getOpcClientRequestId()); + fields(o.getFields()); invocationCallback(o.getInvocationCallback()); return this; } diff --git a/bmc-objectstorage/pom.xml b/bmc-objectstorage/pom.xml index c1558073070..65ddf2a7e22 100644 --- a/bmc-objectstorage/pom.xml +++ b/bmc-objectstorage/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml diff --git a/bmc-resourcesearch/pom.xml b/bmc-resourcesearch/pom.xml index ece52fd1adf..ecd3fef20ca 100644 --- a/bmc-resourcesearch/pom.xml +++ b/bmc-resourcesearch/pom.xml @@ -4,7 +4,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml oci-java-sdk-resourcesearch @@ -17,7 +17,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.3.1 + 1.3.2 diff --git a/bmc-shaded/bmc-shaded-full/pom.xml b/bmc-shaded/bmc-shaded-full/pom.xml index 15532ff4c38..d98c5289e17 100644 --- a/bmc-shaded/bmc-shaded-full/pom.xml +++ b/bmc-shaded/bmc-shaded-full/pom.xml @@ -4,7 +4,7 @@ com.oracle.oci.sdk oci-java-sdk-shaded - 1.3.1 + 1.3.2 ../pom.xml oci-java-sdk-shaded-full diff --git a/bmc-shaded/pom.xml b/bmc-shaded/pom.xml index 3f31632f231..89d3aa8020a 100644 --- a/bmc-shaded/pom.xml +++ b/bmc-shaded/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 ../pom.xml diff --git a/pom.xml b/pom.xml index 21944ee1516..fef46c9ea91 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.oracle.oci.sdk oci-java-sdk - 1.3.1 + 1.3.2 pom Oracle Cloud Infrastructure SDK This project contains the SDK used for Oracle Cloud Infrastructure @@ -265,6 +265,27 @@ 1.7 + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.16 + + + org.codehaus.mojo.signature + java17 + 1.0 + + + + + animal-sniffer-check + test + + check + + + + org.apache.maven.plugins maven-dependency-plugin @@ -417,6 +438,10 @@ maven-compiler-plugin + + org.codehaus.mojo + animal-sniffer-maven-plugin + maven-source-plugin