diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c820099451..229d948c28e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - N/A +## 1.2.42 - 2018-07-12 +### Added +- Support for tagging Load Balancers in the Load Balancing service +- Support for export options in the File Storage service +- Support for retrieving compartment name and user name as part of events in the Audit service + ## 1.2.41 - 2018-06-28 ### Added - Support for service gateway management in the Networking service diff --git a/bmc-audit/pom.xml b/bmc-audit/pom.xml index 80083919a9f..d623bccc9f7 100644 --- a/bmc-audit/pom.xml +++ b/bmc-audit/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-audit/src/main/java/com/oracle/bmc/audit/model/AuditEvent.java b/bmc-audit/src/main/java/com/oracle/bmc/audit/model/AuditEvent.java index 2c9a334e344..6718ae2bc9f 100644 --- a/bmc-audit/src/main/java/com/oracle/bmc/audit/model/AuditEvent.java +++ b/bmc-audit/src/main/java/com/oracle/bmc/audit/model/AuditEvent.java @@ -39,6 +39,15 @@ public Builder compartmentId(String compartmentId) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("compartmentName") + private String compartmentName; + + public Builder compartmentName(String compartmentName) { + this.compartmentName = compartmentName; + this.__explicitlySet__.add("compartmentName"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("eventId") private String eventId; @@ -204,6 +213,15 @@ public Builder responsePayload(java.util.Map responsePayload) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("userName") + private String userName; + + public Builder userName(String userName) { + this.userName = userName; + this.__explicitlySet__.add("userName"); + return this; + } + @com.fasterxml.jackson.annotation.JsonIgnore private final java.util.Set __explicitlySet__ = new java.util.HashSet(); @@ -212,6 +230,7 @@ public AuditEvent build() { new AuditEvent( tenantId, compartmentId, + compartmentName, eventId, eventName, eventSource, @@ -229,7 +248,8 @@ public AuditEvent build() { responseHeaders, responseStatus, responseTime, - responsePayload); + responsePayload, + userName); __instance__.__explicitlySet__.addAll(__explicitlySet__); return __instance__; } @@ -239,6 +259,7 @@ public Builder copy(AuditEvent o) { Builder copiedBuilder = tenantId(o.getTenantId()) .compartmentId(o.getCompartmentId()) + .compartmentName(o.getCompartmentName()) .eventId(o.getEventId()) .eventName(o.getEventName()) .eventSource(o.getEventSource()) @@ -256,7 +277,8 @@ public Builder copy(AuditEvent o) { .responseHeaders(o.getResponseHeaders()) .responseStatus(o.getResponseStatus()) .responseTime(o.getResponseTime()) - .responsePayload(o.getResponsePayload()); + .responsePayload(o.getResponsePayload()) + .userName(o.getUserName()); copiedBuilder.__explicitlySet__.retainAll(o.__explicitlySet__); return copiedBuilder; @@ -282,6 +304,14 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("compartmentId") String compartmentId; + /** + * The name of the compartment. This value is the friendly name associated with compartmentId. + * This value can change, but the service logs the value that appeared at the time of the audit event. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("compartmentName") + String compartmentName; + /** * The GUID of the event. **/ @@ -392,6 +422,12 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("responsePayload") java.util.Map responsePayload; + /** + * The name of the user or service. This value is the friendly name associated with principalId. + **/ + @com.fasterxml.jackson.annotation.JsonProperty("userName") + String userName; + @com.fasterxml.jackson.annotation.JsonIgnore private final java.util.Set __explicitlySet__ = new java.util.HashSet(); } diff --git a/bmc-bom/pom.xml b/bmc-bom/pom.xml index 1e5374961ec..6ecd1917ce4 100644 --- a/bmc-bom/pom.xml +++ b/bmc-bom/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml oci-java-sdk-bom @@ -19,68 +19,68 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-audit - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-containerengine - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-core - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-database - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-dns - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-email - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-filestorage - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-identity - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-loadbalancer - 1.2.41 + 1.2.42 false com.oracle.oci.sdk oci-java-sdk-objectstorage - 1.2.41 + 1.2.42 false pom diff --git a/bmc-common/pom.xml b/bmc-common/pom.xml index 560a961b465..87b01a497e8 100644 --- a/bmc-common/pom.xml +++ b/bmc-common/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml 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 6bf1d0cb5cc..d07af85b451 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 @@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; @@ -304,17 +305,14 @@ private SecurityTokenAdapter getSecurityTokenFromServer() { } // really simple retry until the SDK supports internal retries - private Response makeCall(Builder ib, X509FederationRequest federationRequest) { + @VisibleForTesting + Response makeCall(Builder ib, X509FederationRequest federationRequest) { BmcException lastException = null; + // Keeping one instance of the WrappedInvocationBuilder in order to preserve the request ID on retries. + final WrappedInvocationBuilder wrappedIb = new WrappedInvocationBuilder(ib); for (int retry = 0; retry < 5; retry++) { try { - // we don't have a wrapper object for the request, just give a new object - Response response = - federationHttpClient.post( - new WrappedInvocationBuilder(ib), - federationRequest, - new BmcRequest()); - return response; + return federationHttpClient.post(wrappedIb, federationRequest, new BmcRequest()); } catch (BmcException e) { // retry in all cases right now lastException = e; diff --git a/bmc-common/src/main/java/com/oracle/bmc/http/signing/RequestSignerException.java b/bmc-common/src/main/java/com/oracle/bmc/http/signing/RequestSignerException.java new file mode 100644 index 00000000000..2da2327a7e5 --- /dev/null +++ b/bmc-common/src/main/java/com/oracle/bmc/http/signing/RequestSignerException.java @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.http.signing; + +public class RequestSignerException extends RuntimeException { + public RequestSignerException(final String msg) { + super(msg); + } + + public RequestSignerException(final String msg, final Throwable cause) { + super(msg, cause); + } +} diff --git a/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/RequestSignerImpl.java b/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/RequestSignerImpl.java index 1a6309e1e3e..8b0f7725b3c 100644 --- a/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/RequestSignerImpl.java +++ b/bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/RequestSignerImpl.java @@ -21,6 +21,8 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import com.google.common.annotations.VisibleForTesting; +import com.oracle.bmc.http.signing.RequestSignerException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; @@ -180,14 +182,14 @@ private Version validateVersion(String version, Algorithm algorithm) { final Optional oVersion = SignedRequestVersion.getVersion(version); if (!oVersion.isPresent()) { LOG.debug("Invalid version number '{}'", version); - throw new RuntimeException("Invalid version number"); + throw new RequestSignerException("Invalid version number"); } final Version srVersion = oVersion.get(); final Optional errorOpt = srVersion.validateAlgorithm(algorithm); if (errorOpt.isPresent()) { LOG.debug("Signature version rule validation failed '{}'", errorOpt.get()); - throw new RuntimeException("Version validation fails " + errorOpt.get()); + throw new RequestSignerException("Version validation fails " + errorOpt.get()); } return srVersion; } @@ -201,23 +203,41 @@ private RSAPrivateKey getPrivateKey(String keyId) { // having caller dealing with exception if (!keyOptional.isPresent()) { LOG.debug("Could not find private key associated with keyId '{}'", keyId); - throw new RuntimeException("Could not find private key"); + throw new RequestSignerException("Could not find private key"); } return keyOptional.get(); } - private Map ignoreCaseHeaders(final Map> originalHeaders) { + @VisibleForTesting + static Map ignoreCaseHeaders(Map> originalHeaders) { Map transformedMap = new HashMap<>(); for (Entry> entry : originalHeaders.entrySet()) { if (entry.getValue().size() != 1) { - throw new RuntimeException( - "Expecting exactly one value for header " + entry.getKey()); + final String headerKey = entry.getKey(); + final RequestSignerException exception = + new RequestSignerException( + "Expecting exactly one value for header " + headerKey); + LOG.error( + "More than one value for header [{}] found. All headers: {}", + headerKey, + transformHeadersToJsonString(originalHeaders), + exception); + throw exception; } transformedMap.put(entry.getKey().toLowerCase(Locale.ROOT), entry.getValue().get(0)); } return transformedMap; } + private static String transformHeadersToJsonString(Map> headers) { + try { + return RestClientFactory.getObjectMapper().writeValueAsString(headers); + } catch (JsonProcessingException ex) { + LOG.debug("Unable to serialize headers to JSON string", ex); + return "UNABLE TO SERIALIZE"; + } + } + private static String extractPath(URI uri) { String path = uri.getRawPath(); String query = uri.getRawQuery(); @@ -251,7 +271,7 @@ private Map calculateMissingHeaders( if (!(isPut || isPost || isPatch)) { // Asking to sign a body on GET/DELETE/HEAD is not allowed if (body != null) { - throw new RuntimeException("MUST NOT send body on non-POST/PUT request"); + throw new RequestSignerException("MUST NOT send body on non-POST/PUT request"); } else { // nothing left to do return missingHeaders; diff --git a/bmc-common/src/test/java/com/oracle/bmc/auth/internal/X509FederationClientTest.java b/bmc-common/src/test/java/com/oracle/bmc/auth/internal/X509FederationClientTest.java new file mode 100644 index 00000000000..fc25bc6deee --- /dev/null +++ b/bmc-common/src/test/java/com/oracle/bmc/auth/internal/X509FederationClientTest.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.auth.internal; + +import com.oracle.bmc.auth.SessionKeySupplier; +import com.oracle.bmc.auth.X509CertificateSupplier; +import com.oracle.bmc.http.ClientConfigurator; +import com.oracle.bmc.http.internal.RestClient; +import com.oracle.bmc.http.internal.WrappedInvocationBuilder; +import com.oracle.bmc.model.BmcException; +import com.oracle.bmc.requests.BmcRequest; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.Response; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.whenNew; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ + RestClientUtils.class, + Thread.class, + X509FederationClient.class, + WrappedInvocationBuilder.class +}) +public class X509FederationClientTest { + + @Mock private RestClient mockFederationClient; + @Captor private ArgumentCaptor wrappedIbCaptor; + private X509FederationClient clientUnderTest; + + @Before + public void setUp() { + mockStatic(RestClientUtils.class); + when( + RestClientUtils.createRestClient( + anyString(), + any(ClientConfigurator.class), + any(X509FederationClient.class))) + .thenReturn(mockFederationClient); + + final Set intermediateCertificateSuppliers = + Collections.emptySet(); + clientUnderTest = + new X509FederationClient( + "federationEndpoint", + "tenantId", + mock(X509CertificateSupplier.class), + mock(SessionKeySupplier.class), + intermediateCertificateSuppliers, + mock(ClientConfigurator.class)); + + // Speed up the tests to mock out the sleep call between retries + mockStatic(Thread.class); + } + + @Test + public void makeCall_shouldReuseWrappedInvocationBuilderReference_whenBmcExceptionIsThrown() + throws Exception { + // Set up WrappedInvocationBuilder used to verify + final WrappedInvocationBuilder expectedWIb = mock(WrappedInvocationBuilder.class); + final Invocation.Builder ib = mock(Invocation.Builder.class); + whenNew(WrappedInvocationBuilder.class).withArguments(eq(ib)).thenReturn(expectedWIb); + final Response expectedResponse = mock(Response.class); + + // Stub exceptions thrown by the client 3 consecutive times then a successful + when( + mockFederationClient.post( + any(WrappedInvocationBuilder.class), + any(X509FederationClient.X509FederationRequest.class), + any(BmcRequest.class))) + .thenThrow(new BmcException(409, "ServiceCode", "Exception 1", "RequestId")) + .thenThrow(new BmcException(409, "ServiceCode", "Exception 2", "RequestId")) + .thenThrow(new BmcException(409, "ServiceCode", "Exception 3", "RequestId")) + .thenReturn(expectedResponse); + + // Method under test. + final Response actualResponse = + clientUnderTest.makeCall( + ib, mock(X509FederationClient.X509FederationRequest.class)); + + assertEquals("Response should be equal", expectedResponse, actualResponse); + verify(mockFederationClient, times(4)) + .post( + wrappedIbCaptor.capture(), + isA(X509FederationClient.X509FederationRequest.class), + isA(BmcRequest.class)); + final List wrappedIbsFromInvocation = + wrappedIbCaptor.getAllValues(); + assertFalse( + "Captured list of WrappedInvocationBuilder should not be empty", + wrappedIbsFromInvocation.isEmpty()); + assertEquals( + "Captured list of WrappedInvocationBuilder size should be 4", + 4 /* expected number of captures */, + wrappedIbsFromInvocation.size()); + for (WrappedInvocationBuilder actualWib : wrappedIbsFromInvocation) { + assertEquals("Captured WIB should be the same", expectedWIb, actualWib); + } + } +} diff --git a/bmc-common/src/test/java/com/oracle/bmc/http/CompositeClientConfiguratorTest.java b/bmc-common/src/test/java/com/oracle/bmc/http/CompositeClientConfiguratorTest.java index 0b6959f8918..ec3c6f30914 100644 --- a/bmc-common/src/test/java/com/oracle/bmc/http/CompositeClientConfiguratorTest.java +++ b/bmc-common/src/test/java/com/oracle/bmc/http/CompositeClientConfiguratorTest.java @@ -13,7 +13,7 @@ import javax.ws.rs.client.ClientBuilder; import java.util.Arrays; -import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -39,8 +39,8 @@ public void testCompositeConfigurator_happyCase() { verify(mockBuilder).register(argThat(new StringArgVerifier("B"))); compositeConfigurator.customizeClient(mockClient); - verify(mockClient).target(argThat(new StringArgVerifier("A"))); - verify(mockClient).target(argThat(new StringArgVerifier("B"))); + verify(mockClient).target((String) argThat(new StringArgVerifier("A"))); + verify(mockClient).target((String) argThat(new StringArgVerifier("B"))); } //Below we have two sample configurators implemented. We call a methods with bogus values just so we can @@ -72,11 +72,11 @@ public void customizeBuilder(javax.ws.rs.client.ClientBuilder builder) { // We can't use lambdas, so we define Matchers here to verify what args a mock was called with. @AllArgsConstructor - private static final class StringArgVerifier implements ArgumentMatcher { + private static final class StringArgVerifier extends ArgumentMatcher { @NonNull private final String expectedString; @Override - public boolean matches(String s) { + public boolean matches(Object s) { return expectedString.equals(s); } } diff --git a/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/RequestSignerImplTest.java b/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/RequestSignerImplTest.java new file mode 100644 index 00000000000..1f3221ed2e9 --- /dev/null +++ b/bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/RequestSignerImplTest.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.http.signing.internal; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import com.oracle.bmc.http.internal.RestClientFactory; +import com.oracle.bmc.http.signing.RequestSignerException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.core.MediaType; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({LoggerFactory.class, RestClientFactory.class, RequestSignerImpl.class}) +public class RequestSignerImplTest { + private static final String SERIALIZED_MAP_JSON_STRING = "{\"header\":[\"value1\",\"value2\"]}"; + + @Mock private Logger mockLogger; + @Mock private ObjectMapper mockObjectMapper; + + @Before + public void setUp() throws Exception { + mockStatic(LoggerFactory.class); + when(LoggerFactory.getLogger(any(Class.class))).thenReturn(mockLogger); + + mockStatic(LoggerFactory.class); + when(LoggerFactory.getLogger(any(Class.class))).thenReturn(mockLogger); + + mockStatic(RestClientFactory.class); + when(RestClientFactory.getObjectMapper()).thenReturn(mockObjectMapper); + when(mockObjectMapper.writeValueAsString(any())).thenReturn(SERIALIZED_MAP_JSON_STRING); + } + + @Test + public void ignoreCaseHeaders_shouldReturnMapWithLowerCaseKeys_whenHeadersContainUpperCaseKeys() + throws Exception { + final Map> headers = new HashMap<>(); + headers.put("Content-Length", Collections.singletonList("238")); + headers.put("Content-Type", Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.put("OPC-REQUEST-ID", Collections.singletonList("RequestID")); + + final Map actual = RequestSignerImpl.ignoreCaseHeaders(headers); + + assertNotNull("Map should not be null", actual); + assertEquals("Map should contain 3 entries", 3, actual.size()); + for (Map.Entry> expectedEntry : headers.entrySet()) { + final String expectedKey = expectedEntry.getKey(); + final String expectedValue = expectedEntry.getValue().get(0); + + assertTrue( + "Actual map should contain matching key for lower case value", + actual.containsKey(expectedKey.toLowerCase())); + final String actualValue = actual.get(expectedKey.toLowerCase()); + assertEquals( + "Values should be equal for key: " + expectedKey, expectedValue, actualValue); + } + } + + // Reload the classes so PowerMockito can inject the static mocks. + @PrepareForTest({LoggerFactory.class, RestClientFactory.class, RequestSignerImpl.class}) + @Test + public void ignoreCaseHeaders_shouldThrowRequestSignerException_whenDuplicateHeaderKeysExists() + throws Exception { + final Map> headers = new HashMap<>(); + headers.put("content-length", Collections.singletonList("238")); + headers.put("opc-request-id", Lists.newArrayList("ID1", "ID2")); + + try { + RequestSignerImpl.ignoreCaseHeaders(headers); + fail("RequestSignerException should have been thrown"); + } catch (RequestSignerException ex) { + assertTrue( + "Exception message should contain key with duplicate entries", + ex.getMessage() + .contains("Expecting exactly one value for header opc-request-id")); + verify(mockObjectMapper).writeValueAsString(eq(headers)); + + final ArgumentCaptor logMessageCaptor = ArgumentCaptor.forClass(String.class); + verify(mockLogger) + .error( + logMessageCaptor.capture(), + eq("opc-request-id"), + eq(SERIALIZED_MAP_JSON_STRING), + eq(ex)); + + final String actaulLogMessageValue = logMessageCaptor.getValue(); + assertTrue( + "Logging messages should contain the base message", + actaulLogMessageValue.contains("More than one value for header [{}] found.")); + } + } +} 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 4428ebe2ab9..1e8d5b4538d 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 @@ -3,30 +3,29 @@ */ package com.oracle.bmc.util.internal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.oracle.bmc.http.internal.WrappedWebTarget; import org.junit.Ignore; import org.junit.Test; -import org.mockito.ArgumentMatchers; import org.mockito.Mockito; import javax.ws.rs.client.WebTarget; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + public class HttpUtilsTest { @Test(expected = IllegalArgumentException.class) @@ -94,7 +93,7 @@ public void encodeMapQueryParam_mapOfStringToBoolean() { WebTarget target = mock(WebTarget.class); - when(target.queryParam(anyString(), ArgumentMatchers.any())).thenReturn(target); + when(target.queryParam(anyString(), any())).thenReturn(target); WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeMapQueryParam(wrapped, prefix, definedTagsExists); @@ -124,7 +123,7 @@ public void attemptEncodeQueryParam_mapOfStringToListOfString() WebTarget target = mock(WebTarget.class); - when(target.queryParam(anyString(), ArgumentMatchers.any())).thenReturn(target); + when(target.queryParam(anyString(), any())).thenReturn(target); WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeMapQueryParam(wrapped, prefix, definedTags); @@ -161,7 +160,7 @@ public void encodeMapQueryParam_mapOfStringToBoolean_nullPrefix() { WebTarget target = mock(WebTarget.class); - when(target.queryParam(anyString(), ArgumentMatchers.any())).thenReturn(target); + when(target.queryParam(anyString(), any())).thenReturn(target); WrappedWebTarget wrapped = new WrappedWebTarget(target); WrappedWebTarget result = HttpUtils.encodeMapQueryParam(wrapped, prefix, definedTagsExists); diff --git a/bmc-containerengine/pom.xml b/bmc-containerengine/pom.xml index 850a69312cf..d695afa8df2 100644 --- a/bmc-containerengine/pom.xml +++ b/bmc-containerengine/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-core/pom.xml b/bmc-core/pom.xml index edd17d1a812..43fa77f8305 100644 --- a/bmc-core/pom.xml +++ b/bmc-core/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-database/pom.xml b/bmc-database/pom.xml index 5b569782c27..94d55752a71 100644 --- a/bmc-database/pom.xml +++ b/bmc-database/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-dns/pom.xml b/bmc-dns/pom.xml index aac05c38dc1..34bbd38f211 100644 --- a/bmc-dns/pom.xml +++ b/bmc-dns/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-email/pom.xml b/bmc-email/pom.xml index 42f435fe8c2..b965bd9d8ff 100644 --- a/bmc-email/pom.xml +++ b/bmc-email/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-examples/pom.xml b/bmc-examples/pom.xml index bc8b2431728..bbfc2d4d4f8 100644 --- a/bmc-examples/pom.xml +++ b/bmc-examples/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -19,7 +19,7 @@ com.oracle.oci.sdk oci-java-sdk-bom - 1.2.41 + 1.2.42 pom import diff --git a/bmc-filestorage/pom.xml b/bmc-filestorage/pom.xml index b149bda0342..52d08a99e3c 100644 --- a/bmc-filestorage/pom.xml +++ b/bmc-filestorage/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorage.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorage.java index bcdca2c6f8d..9d0fd3df692 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorage.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorage.java @@ -256,6 +256,14 @@ public interface FileStorage extends AutoCloseable { */ ListSnapshotsResponse listSnapshots(ListSnapshotsRequest request); + /** + * Updates the specified export's information. + * @param request The request object containing the details to send + * @return A response object containing details about the completed operation + * @throws BmcException when an error occurs. + */ + UpdateExportResponse updateExport(UpdateExportRequest request); + /** * Updates the specified export set's information. * @param request The request object containing the details to send diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsync.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsync.java index a8127ed8e70..73839a5637b 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsync.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsync.java @@ -381,6 +381,21 @@ java.util.concurrent.Future listSnapshots( com.oracle.bmc.responses.AsyncHandler handler); + /** + * Updates the specified export's information. + * + * @param request The request object containing the details to send + * @param handler The request handler to invoke upon completion, may be null. + * @return A Future that can be used to get the response if no AsyncHandler was + * provided. Note, if you provide an AsyncHandler and use the Future, some + * types of responses (like java.io.InputStream) may not be able to be read in + * both places as the underlying stream may only be consumed once. + */ + java.util.concurrent.Future updateExport( + UpdateExportRequest request, + com.oracle.bmc.responses.AsyncHandler + handler); + /** * Updates the specified export set's information. * diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsyncClient.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsyncClient.java index 206df4d3618..c0b8f7e01cc 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsyncClient.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageAsyncClient.java @@ -1578,6 +1578,89 @@ public java.util.concurrent.Future get() { } } + @Override + public java.util.concurrent.Future updateExport( + final UpdateExportRequest request, + final com.oracle.bmc.responses.AsyncHandler + handler) { + LOG.trace("Called async updateExport"); + final UpdateExportRequest interceptedRequest = + UpdateExportConverter.interceptRequest(request); + final com.oracle.bmc.http.internal.WrappedInvocationBuilder ib = + UpdateExportConverter.fromRequest(client, interceptedRequest); + final com.google.common.base.Function + transformer = UpdateExportConverter.fromResponse(); + + com.oracle.bmc.responses.AsyncHandler + handlerToUse = handler; + if (handler != null + && this.authenticationDetailsProvider + instanceof com.oracle.bmc.auth.RefreshableOnNotAuthenticatedProvider) { + handlerToUse = + new com.oracle.bmc.util.internal.RefreshAuthTokenWrappingAsyncHandler< + UpdateExportRequest, UpdateExportResponse>( + (com.oracle.bmc.auth.RefreshableOnNotAuthenticatedProvider) + this.authenticationDetailsProvider, + handler) { + @Override + public void retryCall() { + final com.oracle.bmc.util.internal.Consumer + onSuccess = + new com.oracle.bmc.http.internal.SuccessConsumer<>( + this, transformer, interceptedRequest); + final com.oracle.bmc.util.internal.Consumer onError = + new com.oracle.bmc.http.internal.ErrorConsumer<>( + this, interceptedRequest); + client.put( + ib, + interceptedRequest.getUpdateExportDetails(), + interceptedRequest, + onSuccess, + onError); + } + }; + } + + final com.oracle.bmc.util.internal.Consumer onSuccess = + new com.oracle.bmc.http.internal.SuccessConsumer<>( + handlerToUse, transformer, interceptedRequest); + final com.oracle.bmc.util.internal.Consumer onError = + new com.oracle.bmc.http.internal.ErrorConsumer<>(handlerToUse, interceptedRequest); + + java.util.concurrent.Future responseFuture = + client.put( + ib, + interceptedRequest.getUpdateExportDetails(), + interceptedRequest, + onSuccess, + onError); + + if (this.authenticationDetailsProvider + instanceof com.oracle.bmc.auth.RefreshableOnNotAuthenticatedProvider) { + return new com.oracle.bmc.util.internal.RefreshAuthTokenTransformingFuture< + javax.ws.rs.core.Response, UpdateExportResponse>( + responseFuture, + transformer, + (com.oracle.bmc.auth.RefreshableOnNotAuthenticatedProvider) + this.authenticationDetailsProvider, + new com.google.common.base.Supplier< + java.util.concurrent.Future>() { + @Override + public java.util.concurrent.Future get() { + return client.put( + ib, + interceptedRequest.getUpdateExportDetails(), + interceptedRequest, + onSuccess, + onError); + } + }); + } else { + return new com.oracle.bmc.util.internal.TransformingFuture<>( + responseFuture, transformer); + } + } + @Override public java.util.concurrent.Future updateExportSet( final UpdateExportSetRequest request, diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageClient.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageClient.java index 5116cbdc69e..ac6853b5d7c 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageClient.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/FileStorageClient.java @@ -762,6 +762,32 @@ && canRetryRequestIfRefreshableAuthTokenUsed(e)) { } } + @Override + public UpdateExportResponse updateExport(UpdateExportRequest request) { + LOG.trace("Called updateExport"); + request = UpdateExportConverter.interceptRequest(request); + com.oracle.bmc.http.internal.WrappedInvocationBuilder ib = + UpdateExportConverter.fromRequest(client, request); + com.google.common.base.Function + transformer = UpdateExportConverter.fromResponse(); + + int attempts = 0; + while (true) { + try { + javax.ws.rs.core.Response response = + client.put(ib, request.getUpdateExportDetails(), request); + return transformer.apply(response); + } catch (com.oracle.bmc.model.BmcException e) { + if (++attempts < MAX_IMMEDIATE_RETRIES_IF_USING_INSTANCE_PRINCIPALS + && canRetryRequestIfRefreshableAuthTokenUsed(e)) { + continue; + } else { + throw e; + } + } + } + } + @Override public UpdateExportSetResponse updateExportSet(UpdateExportSetRequest request) { LOG.trace("Called updateExportSet"); diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/internal/http/UpdateExportConverter.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/internal/http/UpdateExportConverter.java new file mode 100644 index 00000000000..5ef00d0eded --- /dev/null +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/internal/http/UpdateExportConverter.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.filestorage.internal.http; + +import com.oracle.bmc.filestorage.model.*; +import com.oracle.bmc.filestorage.requests.*; +import com.oracle.bmc.filestorage.responses.*; +import org.apache.commons.lang3.Validate; + +@javax.annotation.Generated(value = "OracleSDKGenerator", comments = "API Version: 20171215") +@lombok.extern.slf4j.Slf4j +public class UpdateExportConverter { + private static final com.oracle.bmc.http.internal.ResponseConversionFunctionFactory + RESPONSE_CONVERSION_FACTORY = + new com.oracle.bmc.http.internal.ResponseConversionFunctionFactory(); + + public static UpdateExportRequest interceptRequest(UpdateExportRequest request) { + + return request; + } + + public static com.oracle.bmc.http.internal.WrappedInvocationBuilder fromRequest( + com.oracle.bmc.http.internal.RestClient client, UpdateExportRequest request) { + Validate.notNull(request, "request instance is required"); + Validate.notBlank(request.getExportId(), "exportId must not be blank"); + Validate.notNull(request.getUpdateExportDetails(), "updateExportDetails is required"); + + com.oracle.bmc.http.internal.WrappedWebTarget target = + client.getBaseTarget() + .path("/20171215") + .path("exports") + .path( + com.oracle.bmc.util.internal.HttpUtils.encodePathSegment( + request.getExportId())); + + com.oracle.bmc.http.internal.WrappedInvocationBuilder ib = target.request(); + + ib.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON); + + if (request.getIfMatch() != null) { + ib.header("if-match", request.getIfMatch()); + } + + return ib; + } + + public static com.google.common.base.Function + fromResponse() { + final com.google.common.base.Function + transformer = + new com.google.common.base.Function< + javax.ws.rs.core.Response, UpdateExportResponse>() { + @Override + public UpdateExportResponse apply( + javax.ws.rs.core.Response rawResponse) { + LOG.trace("Transform function invoked for UpdateExportResponse"); + com.google.common.base.Function< + javax.ws.rs.core.Response, + com.oracle.bmc.http.internal.WithHeaders> + responseFn = + RESPONSE_CONVERSION_FACTORY.create(Export.class); + + com.oracle.bmc.http.internal.WithHeaders response = + responseFn.apply(rawResponse); + javax.ws.rs.core.MultivaluedMap headers = + response.getHeaders(); + + UpdateExportResponse.Builder builder = + UpdateExportResponse.builder(); + + builder.export(response.getItem()); + + com.google.common.base.Optional> etagHeader = + com.oracle.bmc.http.internal.HeaderUtils.get( + headers, "etag"); + if (etagHeader.isPresent()) { + builder.etag( + com.oracle.bmc.http.internal.HeaderUtils.toValue( + "etag", etagHeader.get().get(0), String.class)); + } + + com.google.common.base.Optional> + opcRequestIdHeader = + com.oracle.bmc.http.internal.HeaderUtils.get( + headers, "opc-request-id"); + if (opcRequestIdHeader.isPresent()) { + builder.opcRequestId( + com.oracle.bmc.http.internal.HeaderUtils.toValue( + "opc-request-id", + opcRequestIdHeader.get().get(0), + String.class)); + } + + UpdateExportResponse responseWrapper = builder.build(); + + return responseWrapper; + } + }; + return transformer; + } +} diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ClientOptions.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ClientOptions.java new file mode 100644 index 00000000000..2f48d1f141b --- /dev/null +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ClientOptions.java @@ -0,0 +1,281 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.filestorage.model; + +/** + * NFS export options applied to a specified set of + * clients. Only governs access through the associated + * export. Access to the same file system through a different + * export (on the same or different mount target) will be governed + * by that export's export options. + * + *
+ * Note: This model distinguishes fields that are {@code null} because they are unset from fields that are explicitly + * set to {@code null}. This is done in the setter methods of the {@link Builder}, which maintain a set of all + * explicitly set fields called {@link #__explicitlySet__}. The {@link #hashCode()} and {@link #equals(Object)} methods + * are implemented to take {@link #__explicitlySet__} into account. The constructor, on the other hand, does not + * set {@link #__explicitlySet__} (since the constructor cannot distinguish explicit {@code null} from unset + * {@code null}). As a consequence, objects should always be created or deserialized using the {@link Builder}. + **/ +@javax.annotation.Generated(value = "OracleSDKGenerator", comments = "API Version: 20171215") +@lombok.Value +@com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = ClientOptions.Builder.class) +@com.fasterxml.jackson.annotation.JsonFilter(com.oracle.bmc.http.internal.ExplicitlySetFilter.NAME) +public class ClientOptions { + @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") + @lombok.experimental.Accessors(fluent = true) + public static class Builder { + @com.fasterxml.jackson.annotation.JsonProperty("source") + private String source; + + public Builder source(String source) { + this.source = source; + this.__explicitlySet__.add("source"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonProperty("requirePrivilegedSourcePort") + private Boolean requirePrivilegedSourcePort; + + public Builder requirePrivilegedSourcePort(Boolean requirePrivilegedSourcePort) { + this.requirePrivilegedSourcePort = requirePrivilegedSourcePort; + this.__explicitlySet__.add("requirePrivilegedSourcePort"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonProperty("access") + private Access access; + + public Builder access(Access access) { + this.access = access; + this.__explicitlySet__.add("access"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonProperty("identitySquash") + private IdentitySquash identitySquash; + + public Builder identitySquash(IdentitySquash identitySquash) { + this.identitySquash = identitySquash; + this.__explicitlySet__.add("identitySquash"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonProperty("anonymousUid") + private Long anonymousUid; + + public Builder anonymousUid(Long anonymousUid) { + this.anonymousUid = anonymousUid; + this.__explicitlySet__.add("anonymousUid"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonProperty("anonymousGid") + private Long anonymousGid; + + public Builder anonymousGid(Long anonymousGid) { + this.anonymousGid = anonymousGid; + this.__explicitlySet__.add("anonymousGid"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + private final java.util.Set __explicitlySet__ = new java.util.HashSet(); + + public ClientOptions build() { + ClientOptions __instance__ = + new ClientOptions( + source, + requirePrivilegedSourcePort, + access, + identitySquash, + anonymousUid, + anonymousGid); + __instance__.__explicitlySet__.addAll(__explicitlySet__); + return __instance__; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + public Builder copy(ClientOptions o) { + Builder copiedBuilder = + source(o.getSource()) + .requirePrivilegedSourcePort(o.getRequirePrivilegedSourcePort()) + .access(o.getAccess()) + .identitySquash(o.getIdentitySquash()) + .anonymousUid(o.getAnonymousUid()) + .anonymousGid(o.getAnonymousGid()); + + copiedBuilder.__explicitlySet__.retainAll(o.__explicitlySet__); + return copiedBuilder; + } + } + + /** + * Create a new builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Clients these options should apply to. Must be a either + * single IPv4 address or single IPv4 CIDR block. + *

+ **Note:** Access will also be limited by any applicable VCN + * security rules and the ability to route IP packets to the + * mount target. Mount targets do not have Internet-routable IP addresses. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("source") + String source; + + /** + * If `true`, clients accessing the file system through this + * export must connect from a privileged source port. If + * unspecified, defaults to `true`. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("requirePrivilegedSourcePort") + Boolean requirePrivilegedSourcePort; + /** + * Type of access to grant clients using the file system + * through this export. If unspecified defaults to `READ_ONLY`. + * + **/ + @lombok.extern.slf4j.Slf4j + public enum Access { + ReadWrite("READ_WRITE"), + ReadOnly("READ_ONLY"), + + /** + * This value is used if a service returns a value for this enum that is not recognized by this + * version of the SDK. + */ + UnknownEnumValue(null); + + private final String value; + private static java.util.Map map; + + static { + map = new java.util.HashMap<>(); + for (Access v : Access.values()) { + if (v != UnknownEnumValue) { + map.put(v.getValue(), v); + } + } + } + + Access(String value) { + this.value = value; + } + + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { + return value; + } + + @com.fasterxml.jackson.annotation.JsonCreator + public static Access create(String key) { + if (map.containsKey(key)) { + return map.get(key); + } + LOG.warn( + "Received unknown value '{}' for enum 'Access', returning UnknownEnumValue", + key); + return UnknownEnumValue; + } + }; + /** + * Type of access to grant clients using the file system + * through this export. If unspecified defaults to `READ_ONLY`. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("access") + Access access; + /** + * Used when clients accessing the file system through this export + * have their UID and GID remapped to 'anonymousUid' and + * 'anonymousGid'. If `ALL`, all users and groups are remapped; + * if `ROOT`, only the root user and group (UID/GID 0) are + * remapped; if `NONE`, no remapping is done. If unspecified, + * defaults to `ROOT`. + * + **/ + @lombok.extern.slf4j.Slf4j + public enum IdentitySquash { + None("NONE"), + Root("ROOT"), + All("ALL"), + + /** + * This value is used if a service returns a value for this enum that is not recognized by this + * version of the SDK. + */ + UnknownEnumValue(null); + + private final String value; + private static java.util.Map map; + + static { + map = new java.util.HashMap<>(); + for (IdentitySquash v : IdentitySquash.values()) { + if (v != UnknownEnumValue) { + map.put(v.getValue(), v); + } + } + } + + IdentitySquash(String value) { + this.value = value; + } + + @com.fasterxml.jackson.annotation.JsonValue + public String getValue() { + return value; + } + + @com.fasterxml.jackson.annotation.JsonCreator + public static IdentitySquash create(String key) { + if (map.containsKey(key)) { + return map.get(key); + } + LOG.warn( + "Received unknown value '{}' for enum 'IdentitySquash', returning UnknownEnumValue", + key); + return UnknownEnumValue; + } + }; + /** + * Used when clients accessing the file system through this export + * have their UID and GID remapped to 'anonymousUid' and + * 'anonymousGid'. If `ALL`, all users and groups are remapped; + * if `ROOT`, only the root user and group (UID/GID 0) are + * remapped; if `NONE`, no remapping is done. If unspecified, + * defaults to `ROOT`. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("identitySquash") + IdentitySquash identitySquash; + + /** + * UID value to remap to when squashing a client UID (see + * identitySquash for more details.) If unspecified, defaults + * to `65534`. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("anonymousUid") + Long anonymousUid; + + /** + * GID value to remap to when squashing a client GID (see + * identitySquash for more details.) If unspecified defaults + * to `65534`. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("anonymousGid") + Long anonymousGid; + + @com.fasterxml.jackson.annotation.JsonIgnore + private final java.util.Set __explicitlySet__ = new java.util.HashSet(); +} diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateExportDetails.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateExportDetails.java index b51b3dcb40b..ecdb1f90437 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateExportDetails.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateExportDetails.java @@ -23,6 +23,15 @@ public class CreateExportDetails { @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @lombok.experimental.Accessors(fluent = true) public static class Builder { + @com.fasterxml.jackson.annotation.JsonProperty("exportOptions") + private java.util.List exportOptions; + + public Builder exportOptions(java.util.List exportOptions) { + this.exportOptions = exportOptions; + this.__explicitlySet__.add("exportOptions"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("exportSetId") private String exportSetId; @@ -55,7 +64,7 @@ public Builder path(String path) { public CreateExportDetails build() { CreateExportDetails __instance__ = - new CreateExportDetails(exportSetId, fileSystemId, path); + new CreateExportDetails(exportOptions, exportSetId, fileSystemId, path); __instance__.__explicitlySet__.addAll(__explicitlySet__); return __instance__; } @@ -63,7 +72,8 @@ public CreateExportDetails build() { @com.fasterxml.jackson.annotation.JsonIgnore public Builder copy(CreateExportDetails o) { Builder copiedBuilder = - exportSetId(o.getExportSetId()) + exportOptions(o.getExportOptions()) + .exportSetId(o.getExportSetId()) .fileSystemId(o.getFileSystemId()) .path(o.getPath()); @@ -79,6 +89,34 @@ public static Builder builder() { return new Builder(); } + /** + * Export options for the new export. If left unspecified, + * defaults to: + *

+ * [ + * { + * \"source\" : \"0.0.0.0/0\", + * \"requirePrivilegedSourcePort\" : false, + * \"access\" : \"READ_WRITE\", + * \"identitySquash\" : \"NONE\" + * } + * ] + *

+ **Note:** Mount targets do not have Internet-routable IP + * addresses. Therefore they will not be reachable from the + * Internet, even if an associated `ClientOptions` item has + * a source of `0.0.0.0/0`. + *

+ **If set to the empty array then the export will not be + * visible to any clients.** + *

+ * The export's `exportOptions` can be changed after creation + * using the `UpdateExport` operation. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("exportOptions") + java.util.List exportOptions; + /** * The OCID of this export's export set. **/ diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateSnapshotDetails.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateSnapshotDetails.java index aaddded78c5..f53340c6023 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateSnapshotDetails.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/CreateSnapshotDetails.java @@ -67,7 +67,7 @@ public static Builder builder() { } /** - * The OCID of this export's file system. + * The OCID of the file system to take a snapshot of. **/ @com.fasterxml.jackson.annotation.JsonProperty("fileSystemId") String fileSystemId; diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/Export.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/Export.java index cd6713f8659..42a680d0b16 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/Export.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/Export.java @@ -34,6 +34,9 @@ *

* No two non-'DELETED' export resources in the same export set can * reference the same file system. + *

+ * Use `exportOptions` to control access to an export. For more information, see + * [Export Options](https://docs.us-phoenix-1.oraclecloud.com/Content/File/Tasks/exportoptions.htm). * *
* Note: This model distinguishes fields that are {@code null} because they are unset from fields that are explicitly @@ -51,6 +54,15 @@ public class Export { @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @lombok.experimental.Accessors(fluent = true) public static class Builder { + @com.fasterxml.jackson.annotation.JsonProperty("exportOptions") + private java.util.List exportOptions; + + public Builder exportOptions(java.util.List exportOptions) { + this.exportOptions = exportOptions; + this.__explicitlySet__.add("exportOptions"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("exportSetId") private String exportSetId; @@ -110,7 +122,14 @@ public Builder timeCreated(java.util.Date timeCreated) { public Export build() { Export __instance__ = - new Export(exportSetId, fileSystemId, id, lifecycleState, path, timeCreated); + new Export( + exportOptions, + exportSetId, + fileSystemId, + id, + lifecycleState, + path, + timeCreated); __instance__.__explicitlySet__.addAll(__explicitlySet__); return __instance__; } @@ -118,7 +137,8 @@ public Export build() { @com.fasterxml.jackson.annotation.JsonIgnore public Builder copy(Export o) { Builder copiedBuilder = - exportSetId(o.getExportSetId()) + exportOptions(o.getExportOptions()) + .exportSetId(o.getExportSetId()) .fileSystemId(o.getFileSystemId()) .id(o.getId()) .lifecycleState(o.getLifecycleState()) @@ -137,6 +157,37 @@ public static Builder builder() { return new Builder(); } + /** + * Policies that apply to NFS requests made through this + * export. `exportOptions` contains a sequential list of + * `ClientOptions`. Each `ClientOptions` item defines the + * export options that are applied to a specified + * set of clients. + *

+ * For each NFS request, the first `ClientOptions` option + * in the list whose `source` attribute matches the source + * IP address of the request is applied. + *

+ * If a client source IP address does not match the `source` + * property of any `ClientOptions` in the list, then the + * export will be invisible to that client. This export will + * not be returned by `MOUNTPROC_EXPORT` calls made by the client + * and any attempt to mount or access the file system through + * this export will result in an error. + *

+ **Exports without defined `ClientOptions` are invisible to all clients.** + *

+ * If one export is invisible to a particular client, associated file + * systems may still be accessible through other exports on the same + * or different mount targets. + * To completely deny client access to a file system, be sure that the client + * source IP address is not included in any export for any mount target + * associated with the file system. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("exportOptions") + java.util.List exportOptions; + /** * The OCID of this export's export set. **/ diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ExportSet.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ExportSet.java index 72c2af01333..2701e0cad08 100644 --- a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ExportSet.java +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/ExportSet.java @@ -249,7 +249,7 @@ public static LifecycleState create(String key) { Long maxFsStatBytes; /** - * Controls the maximum `ffiles`, `ffiles`, and `afiles` + * Controls the maximum `tfiles`, `ffiles`, and `afiles` * values reported by `NFS FSSTAT` calls through any associated * mount targets. This is an advanced feature. For most * applications, use the default value. The diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/UpdateExportDetails.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/UpdateExportDetails.java new file mode 100644 index 00000000000..bfd8b9c420d --- /dev/null +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/model/UpdateExportDetails.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.filestorage.model; + +/** + * + *
+ * Note: This model distinguishes fields that are {@code null} because they are unset from fields that are explicitly + * set to {@code null}. This is done in the setter methods of the {@link Builder}, which maintain a set of all + * explicitly set fields called {@link #__explicitlySet__}. The {@link #hashCode()} and {@link #equals(Object)} methods + * are implemented to take {@link #__explicitlySet__} into account. The constructor, on the other hand, does not + * set {@link #__explicitlySet__} (since the constructor cannot distinguish explicit {@code null} from unset + * {@code null}). As a consequence, objects should always be created or deserialized using the {@link Builder}. + **/ +@javax.annotation.Generated(value = "OracleSDKGenerator", comments = "API Version: 20171215") +@lombok.Value +@com.fasterxml.jackson.databind.annotation.JsonDeserialize( + builder = UpdateExportDetails.Builder.class +) +@com.fasterxml.jackson.annotation.JsonFilter(com.oracle.bmc.http.internal.ExplicitlySetFilter.NAME) +public class UpdateExportDetails { + @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") + @lombok.experimental.Accessors(fluent = true) + public static class Builder { + @com.fasterxml.jackson.annotation.JsonProperty("exportOptions") + private java.util.List exportOptions; + + public Builder exportOptions(java.util.List exportOptions) { + this.exportOptions = exportOptions; + this.__explicitlySet__.add("exportOptions"); + return this; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + private final java.util.Set __explicitlySet__ = new java.util.HashSet(); + + public UpdateExportDetails build() { + UpdateExportDetails __instance__ = new UpdateExportDetails(exportOptions); + __instance__.__explicitlySet__.addAll(__explicitlySet__); + return __instance__; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + public Builder copy(UpdateExportDetails o) { + Builder copiedBuilder = exportOptions(o.getExportOptions()); + + copiedBuilder.__explicitlySet__.retainAll(o.__explicitlySet__); + return copiedBuilder; + } + } + + /** + * Create a new builder. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * New export options for the export. + *

+ **Setting to the empty array will make the export invisible to all clients.** + *

+ * Leaving unset will leave the `exportOptions` unchanged. + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("exportOptions") + java.util.List exportOptions; + + @com.fasterxml.jackson.annotation.JsonIgnore + private final java.util.Set __explicitlySet__ = new java.util.HashSet(); +} diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/requests/UpdateExportRequest.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/requests/UpdateExportRequest.java new file mode 100644 index 00000000000..aa6d2006b57 --- /dev/null +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/requests/UpdateExportRequest.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.filestorage.requests; + +import com.oracle.bmc.filestorage.model.*; + +@javax.annotation.Generated(value = "OracleSDKGenerator", comments = "API Version: 20171215") +@lombok.Builder(builderClassName = "Builder", buildMethodName = "buildWithoutInvocationCallback") +@lombok.Getter +public class UpdateExportRequest extends com.oracle.bmc.requests.BmcRequest { + + /** + * The OCID of the export. + */ + private String exportId; + + /** + * Details object for updating an export. + */ + private UpdateExportDetails updateExportDetails; + + /** + * For optimistic concurrency control. In the PUT or DELETE call + * for a resource, set the `if-match` parameter to the value of the + * etag from a previous GET or POST response for that resource. + * The resource will be updated or deleted only if the etag you + * provide matches the resource's current etag value. + * + */ + private String ifMatch; + + public static class Builder { + private com.oracle.bmc.util.internal.Consumer + invocationCallback = null; + + /** + * Set the invocation callback for the request to be built. + * @param invocationCallback the invocation callback to be set for the request + * @return this builder instance + */ + public Builder invocationCallback( + com.oracle.bmc.util.internal.Consumer + invocationCallback) { + this.invocationCallback = invocationCallback; + return this; + } + + /** + * Copy method to populate the builder with values from the given instance. + * @return this builder instance + */ + public Builder copy(UpdateExportRequest o) { + exportId(o.getExportId()); + updateExportDetails(o.getUpdateExportDetails()); + ifMatch(o.getIfMatch()); + invocationCallback(o.getInvocationCallback()); + return this; + } + + /** + * Build the instance of UpdateExportRequest as configured by this builder + * + * Note that this method takes calls to {@link Builder#invocationCallback(com.oracle.bmc.util.internal.Consumer)} into account, + * while the method {@link Builder#buildWithoutInvocationCallback} does not. + * + * This is the preferred method to build an instance. + * + * @return instance of UpdateExportRequest + */ + public UpdateExportRequest build() { + UpdateExportRequest request = buildWithoutInvocationCallback(); + request.setInvocationCallback(invocationCallback); + return request; + } + } +} diff --git a/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/responses/UpdateExportResponse.java b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/responses/UpdateExportResponse.java new file mode 100644 index 00000000000..bc2d841fefe --- /dev/null +++ b/bmc-filestorage/src/main/java/com/oracle/bmc/filestorage/responses/UpdateExportResponse.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.filestorage.responses; + +import com.oracle.bmc.filestorage.model.*; + +@javax.annotation.Generated(value = "OracleSDKGenerator", comments = "API Version: 20171215") +@lombok.Builder(builderClassName = "Builder") +@lombok.Getter +public class UpdateExportResponse { + + /** + * For optimistic concurrency control. See `if-match`. + */ + private String etag; + + /** + * Unique Oracle-assigned identifier for the request. If + * you need to contact Oracle about a particular request, + * please provide the request ID. + * + */ + private String opcRequestId; + + /** + * The returned Export instance. + */ + private Export export; + + public static class Builder { + /** + * Copy method to populate the builder with values from the given instance. + * @return this builder instance + */ + public Builder copy(UpdateExportResponse o) { + etag(o.getEtag()); + opcRequestId(o.getOpcRequestId()); + export(o.getExport()); + + return this; + } + } +} diff --git a/bmc-full/pom.xml b/bmc-full/pom.xml index 37d011bc39a..d4df9381848 100644 --- a/bmc-full/pom.xml +++ b/bmc-full/pom.xml @@ -4,7 +4,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml oci-java-sdk-full @@ -16,7 +16,7 @@ com.oracle.oci.sdk oci-java-sdk-bom - 1.2.41 + 1.2.42 pom import diff --git a/bmc-identity/pom.xml b/bmc-identity/pom.xml index db8755249ae..4dd8fe3d20a 100644 --- a/bmc-identity/pom.xml +++ b/bmc-identity/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-loadbalancer/pom.xml b/bmc-loadbalancer/pom.xml index 01751757e88..7e3c9a2f3ce 100644 --- a/bmc-loadbalancer/pom.xml +++ b/bmc-loadbalancer/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/CreateLoadBalancerDetails.java b/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/CreateLoadBalancerDetails.java index 7a3c3042002..8ee78209ed4 100644 --- a/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/CreateLoadBalancerDetails.java +++ b/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/CreateLoadBalancerDetails.java @@ -50,6 +50,16 @@ public Builder compartmentId(String compartmentId) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("definedTags") + private java.util.Map> definedTags; + + public Builder definedTags( + java.util.Map> definedTags) { + this.definedTags = definedTags; + this.__explicitlySet__.add("definedTags"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("displayName") private String displayName; @@ -59,6 +69,15 @@ public Builder displayName(String displayName) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("freeformTags") + private java.util.Map freeformTags; + + public Builder freeformTags(java.util.Map freeformTags) { + this.freeformTags = freeformTags; + this.__explicitlySet__.add("freeformTags"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("hostnames") private java.util.Map hostnames; @@ -122,7 +141,9 @@ public CreateLoadBalancerDetails build() { backendSets, certificates, compartmentId, + definedTags, displayName, + freeformTags, hostnames, isPrivate, listeners, @@ -139,7 +160,9 @@ public Builder copy(CreateLoadBalancerDetails o) { backendSets(o.getBackendSets()) .certificates(o.getCertificates()) .compartmentId(o.getCompartmentId()) + .definedTags(o.getDefinedTags()) .displayName(o.getDisplayName()) + .freeformTags(o.getFreeformTags()) .hostnames(o.getHostnames()) .isPrivate(o.getIsPrivate()) .listeners(o.getListeners()) @@ -171,6 +194,16 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("compartmentId") String compartmentId; + /** + * Defined tags for this resource. Each key is predefined and scoped to a namespace. + * For more information, see [Resource Tags](https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/resourcetags.htm). + *

+ * Example: `{\"Operations\": {\"CostCenter\": \"42\"}}` + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("definedTags") + java.util.Map> definedTags; + /** * A user-friendly name. It does not have to be unique, and it is changeable. * Avoid entering confidential information. @@ -181,6 +214,16 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("displayName") String displayName; + /** + * Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + * For more information, see [Resource Tags](https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/resourcetags.htm). + *

+ * Example: `{\"Department\": \"Finance\"}` + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("freeformTags") + java.util.Map freeformTags; + @com.fasterxml.jackson.annotation.JsonProperty("hostnames") java.util.Map hostnames; diff --git a/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/LoadBalancer.java b/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/LoadBalancer.java index 8328a16bcb7..da5c3cdf6e3 100644 --- a/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/LoadBalancer.java +++ b/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/LoadBalancer.java @@ -58,6 +58,16 @@ public Builder compartmentId(String compartmentId) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("definedTags") + private java.util.Map> definedTags; + + public Builder definedTags( + java.util.Map> definedTags) { + this.definedTags = definedTags; + this.__explicitlySet__.add("definedTags"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("displayName") private String displayName; @@ -67,6 +77,15 @@ public Builder displayName(String displayName) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("freeformTags") + private java.util.Map freeformTags; + + public Builder freeformTags(java.util.Map freeformTags) { + this.freeformTags = freeformTags; + this.__explicitlySet__.add("freeformTags"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("hostnames") private java.util.Map hostnames; @@ -166,7 +185,9 @@ public LoadBalancer build() { backendSets, certificates, compartmentId, + definedTags, displayName, + freeformTags, hostnames, id, ipAddresses, @@ -187,7 +208,9 @@ public Builder copy(LoadBalancer o) { backendSets(o.getBackendSets()) .certificates(o.getCertificates()) .compartmentId(o.getCompartmentId()) + .definedTags(o.getDefinedTags()) .displayName(o.getDisplayName()) + .freeformTags(o.getFreeformTags()) .hostnames(o.getHostnames()) .id(o.getId()) .ipAddresses(o.getIpAddresses()) @@ -223,6 +246,16 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("compartmentId") String compartmentId; + /** + * Defined tags for this resource. Each key is predefined and scoped to a namespace. + * For more information, see [Resource Tags](https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/resourcetags.htm). + *

+ * Example: `{\"Operations\": {\"CostCenter\": \"42\"}}` + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("definedTags") + java.util.Map> definedTags; + /** * A user-friendly name. It does not have to be unique, and it is changeable. *

@@ -232,6 +265,16 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("displayName") String displayName; + /** + * Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + * For more information, see [Resource Tags](https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/resourcetags.htm). + *

+ * Example: `{\"Department\": \"Finance\"}` + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("freeformTags") + java.util.Map freeformTags; + @com.fasterxml.jackson.annotation.JsonProperty("hostnames") java.util.Map hostnames; diff --git a/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/UpdateLoadBalancerDetails.java b/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/UpdateLoadBalancerDetails.java index 38635c3a8bc..e4311fdddda 100644 --- a/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/UpdateLoadBalancerDetails.java +++ b/bmc-loadbalancer/src/main/java/com/oracle/bmc/loadbalancer/model/UpdateLoadBalancerDetails.java @@ -23,6 +23,16 @@ public class UpdateLoadBalancerDetails { @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "") @lombok.experimental.Accessors(fluent = true) public static class Builder { + @com.fasterxml.jackson.annotation.JsonProperty("definedTags") + private java.util.Map> definedTags; + + public Builder definedTags( + java.util.Map> definedTags) { + this.definedTags = definedTags; + this.__explicitlySet__.add("definedTags"); + return this; + } + @com.fasterxml.jackson.annotation.JsonProperty("displayName") private String displayName; @@ -32,18 +42,31 @@ public Builder displayName(String displayName) { return this; } + @com.fasterxml.jackson.annotation.JsonProperty("freeformTags") + private java.util.Map freeformTags; + + public Builder freeformTags(java.util.Map freeformTags) { + this.freeformTags = freeformTags; + this.__explicitlySet__.add("freeformTags"); + return this; + } + @com.fasterxml.jackson.annotation.JsonIgnore private final java.util.Set __explicitlySet__ = new java.util.HashSet(); public UpdateLoadBalancerDetails build() { - UpdateLoadBalancerDetails __instance__ = new UpdateLoadBalancerDetails(displayName); + UpdateLoadBalancerDetails __instance__ = + new UpdateLoadBalancerDetails(definedTags, displayName, freeformTags); __instance__.__explicitlySet__.addAll(__explicitlySet__); return __instance__; } @com.fasterxml.jackson.annotation.JsonIgnore public Builder copy(UpdateLoadBalancerDetails o) { - Builder copiedBuilder = displayName(o.getDisplayName()); + Builder copiedBuilder = + definedTags(o.getDefinedTags()) + .displayName(o.getDisplayName()) + .freeformTags(o.getFreeformTags()); copiedBuilder.__explicitlySet__.retainAll(o.__explicitlySet__); return copiedBuilder; @@ -57,6 +80,16 @@ public static Builder builder() { return new Builder(); } + /** + * Defined tags for this resource. Each key is predefined and scoped to a namespace. + * For more information, see [Resource Tags](https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/resourcetags.htm). + *

+ * Example: `{\"Operations\": {\"CostCenter\": \"42\"}}` + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("definedTags") + java.util.Map> definedTags; + /** * The user-friendly display name for the load balancer. It does not have to be unique, and it is changeable. * Avoid entering confidential information. @@ -67,6 +100,16 @@ public static Builder builder() { @com.fasterxml.jackson.annotation.JsonProperty("displayName") String displayName; + /** + * Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. + * For more information, see [Resource Tags](https://docs.us-phoenix-1.oraclecloud.com/Content/General/Concepts/resourcetags.htm). + *

+ * Example: `{\"Department\": \"Finance\"}` + * + **/ + @com.fasterxml.jackson.annotation.JsonProperty("freeformTags") + java.util.Map freeformTags; + @com.fasterxml.jackson.annotation.JsonIgnore private final java.util.Set __explicitlySet__ = new java.util.HashSet(); } diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/pom.xml b/bmc-objectstorage/bmc-objectstorage-extensions/pom.xml index 72e506ec4cf..c6a3df42ea1 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 - 1.2.41 + 1.2.42 ../../pom.xml @@ -18,12 +18,12 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 com.oracle.oci.sdk oci-java-sdk-objectstorage-generated - 1.2.41 + 1.2.42 diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressReporter.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressReporter.java new file mode 100644 index 00000000000..4f0c22ca0f4 --- /dev/null +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressReporter.java @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.objectstorage.transfer; + +public interface ProgressReporter { + /** + * Notification to indicate that progress was made during an upload operation. + * + * @param completed The number of bytes that have been already been uploaded for this operation. + * @param total The total number of bytes to upload for this operation. + */ + void onProgress(final long completed, final long total); +} diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTracker.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTracker.java new file mode 100644 index 00000000000..ba39515f0c5 --- /dev/null +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTracker.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.objectstorage.transfer; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.annotation.concurrent.NotThreadSafe; + +@NotThreadSafe +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) +class ProgressTracker { + @NonNull private final ProgressReporter progressReporter; + private final long totalBytes; + + @Getter(value = AccessLevel.PROTECTED) + private long totalBytesRead = 0; + + void onBytesRead(final long bytesRead) { + totalBytesRead += bytesRead; + if (totalBytesRead < 0 || totalBytesRead > totalBytes) { + throw new IllegalStateException( + String.format( + "IllegalState - bytes read %d causes total bytes read(%d)/total bytes(%d)", + bytesRead, + totalBytesRead, + totalBytes)); + } + progressReporter.onProgress(totalBytesRead, totalBytes); + } + + ProgressTracker reset() { + totalBytesRead = 0; + return this; + } + + protected void invalidateBytesRead(long invalidByteCount) { + if (invalidByteCount > totalBytesRead) { + throw new IllegalStateException( + String.format( + "Cannot invalidate %d bytes when total read bytes is %d", + invalidByteCount, + totalBytesRead)); + } + totalBytesRead -= invalidByteCount; + } +} diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackerFactory.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackerFactory.java new file mode 100644 index 00000000000..59c9129afc4 --- /dev/null +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackerFactory.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.objectstorage.transfer; + +import javax.annotation.concurrent.ThreadSafe; + +abstract class ProgressTrackerFactory { + private static final ProgressTrackerFactory DUMMY_PROGRESS_TRACKER_FACTORY = + new ProgressTrackerFactory() { + @Override + ProgressTracker getProgressTracker() { + return null; + } + }; + + static ProgressTrackerFactory createSingleUploadProgressTrackerFactory( + final ProgressReporter progressReporter, final long totalBytes) { + if (progressReporter == null) { + return DUMMY_PROGRESS_TRACKER_FACTORY; + } + return new SingleUploadProgressTrackerFactory(progressReporter, totalBytes); + } + + static ProgressTrackerFactory createMultiPartUploadProgressTrackerFactory( + final ProgressReporter progressReporter, final long totalBytes) { + if (progressReporter == null) { + return DUMMY_PROGRESS_TRACKER_FACTORY; + } + return new MultiPartUploadProgressTrackerFactory(progressReporter, totalBytes); + } + + abstract ProgressTracker getProgressTracker(); + + private static class SingleUploadProgressTrackerFactory extends ProgressTrackerFactory { + + // This progress tracker is implicitly thread safe by definition since there is only a single upload + // going on (in a single upload thread). + private final ProgressTracker progressTracker; + + private SingleUploadProgressTrackerFactory( + final ProgressReporter progressReporter, final long totalBytes) { + progressTracker = new ProgressTracker(progressReporter, totalBytes); + } + + @Override + ProgressTracker getProgressTracker() { + return progressTracker; + } + } + + private static class MultiPartUploadProgressTrackerFactory extends ProgressTrackerFactory { + private static final ProgressReporter DUMMY_PROGRESS_REPORTER = + new ProgressReporter() { + @Override + public void onProgress(long completed, long total) {} + }; + private final ProgressTracker rootProgressTracker; + + private MultiPartUploadProgressTrackerFactory( + final ProgressReporter progressReporter, final long totalBytes) { + rootProgressTracker = new ProgressTracker(progressReporter, totalBytes); + } + + @Override + ProgressTracker getProgressTracker() { + return new SubProgressTracker(); + } + + /** + * This progress tracker is threadsafe as updates to the aggregate root progress tracker is synchronized. + */ + @ThreadSafe + private class SubProgressTracker extends ProgressTracker { + private SubProgressTracker() { + super(DUMMY_PROGRESS_REPORTER, Long.MAX_VALUE); + } + + @Override + void onBytesRead(final long bytesRead) { + super.onBytesRead(bytesRead); + synchronized (rootProgressTracker) { + rootProgressTracker.onBytesRead(bytesRead); + } + } + + @Override + ProgressTracker reset() { + synchronized (rootProgressTracker) { + rootProgressTracker.invalidateBytesRead(getTotalBytesRead()); + } + return super.reset(); + } + } + } +} diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackingInputStreamFactory.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackingInputStreamFactory.java new file mode 100644 index 00000000000..bc5c35c7b13 --- /dev/null +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackingInputStreamFactory.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.objectstorage.transfer; + +import com.oracle.bmc.io.DuplicatableInputStream; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.io.InputStream; + +class ProgressTrackingInputStreamFactory { + static InputStream create(final InputStream source, final ProgressTracker progressTracker) { + if (progressTracker == null) { + return source; + } + if (source instanceof DuplicatableInputStream) { + return new DuplicatableProgressTrackingInputStream(source, progressTracker); + } + return new ProgressTrackingInputStream(source, progressTracker); + } + + @Slf4j + @RequiredArgsConstructor(access = AccessLevel.PROTECTED) + private static class ProgressTrackingInputStream extends InputStream { + @Getter(value = AccessLevel.PROTECTED) + private final InputStream source; + + @NonNull + @Getter(value = AccessLevel.PROTECTED) + private final ProgressTracker progressTracker; + + @Override + public long skip(long n) throws IOException { + return source.skip(n); + } + + @Override + public int available() throws IOException { + return source.available(); + } + + @Override + public void mark(int readlimit) { + source.mark(readlimit); + } + + @Override + public void reset() throws IOException { + source.reset(); + } + + @Override + public boolean markSupported() { + return source.markSupported(); + } + + @Override + public int read() throws IOException { + final int bytesRead = source.read(); + checkAndReportBytesRead(bytesRead); + return bytesRead; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + final int bytesRead = source.read(b, off, len); + checkAndReportBytesRead(bytesRead); + return bytesRead; + } + + @Override + public int read(byte[] b) throws IOException { + final int bytesRead = source.read(b); + checkAndReportBytesRead(bytesRead); + return bytesRead; + } + + @Override + public void close() throws IOException { + source.close(); + } + + private void checkAndReportBytesRead(final int bytesRead) { + if (bytesRead != -1) { + progressTracker.onBytesRead(bytesRead); + } + } + } + + private final static class DuplicatableProgressTrackingInputStream + extends ProgressTrackingInputStream implements DuplicatableInputStream { + + private DuplicatableProgressTrackingInputStream( + final InputStream source, final ProgressTracker progressTracker) { + super(source, progressTracker); + + if (!(source instanceof DuplicatableInputStream)) { + throw new IllegalStateException("Source MUST be a DuplicatableInputStream"); + } + } + + /** + * The progress tracking input stream resulting from this call will re-use the progress tracker from the parent + * progress tracking input stream after resetting it, thus invalidating the progress tracked by the parent + * stream until now. To ensure correctness of the progress tracking functionality, do NOT read from the parent + * stream after duplicating from it. + * @return The duplicated progress tracking input stream. + */ + @Override + public InputStream duplicate() { + return ProgressTrackingInputStreamFactory.create( + ((DuplicatableInputStream) getSource()).duplicate(), + getProgressTracker().reset()); + } + } +} diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/UploadManager.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/UploadManager.java index 71711bbcd30..d98241fce87 100644 --- a/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/UploadManager.java +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/main/java/com/oracle/bmc/objectstorage/transfer/UploadManager.java @@ -78,6 +78,9 @@ public UploadResponse upload(UploadRequest uploadDetails) { private UploadResponse singleUpload( UploadRequest uploadDetails, InputStream stream, long contentLength) { + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + uploadDetails.progressReporter, contentLength); PutObjectRequest putObjectRequest = uploadDetails.putObjectRequest; if (MultipartUtils.shouldCalculateMd5(uploadConfiguration, putObjectRequest)) { MD5Calculation md5Calculation = @@ -88,7 +91,19 @@ private UploadResponse singleUpload( PutObjectRequest.builder() .copy(putObjectRequest) .contentMD5(md5Calculation.md5) - .putObjectBody(md5Calculation.streamToUse) + .putObjectBody( + ProgressTrackingInputStreamFactory.create( + md5Calculation.streamToUse, + progressTrackerFactory.getProgressTracker())) + .build(); + } else { + putObjectRequest = + PutObjectRequest.builder() + .copy(putObjectRequest) + .putObjectBody( + ProgressTrackingInputStreamFactory.create( + putObjectRequest.getPutObjectBody(), + progressTrackerFactory.getProgressTracker())) .build(); } @@ -104,6 +119,9 @@ private UploadResponse singleUpload( private UploadResponse multipartUpload(UploadRequest uploadDetails) { PutObjectRequest request = uploadDetails.putObjectRequest; + ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createMultiPartUploadProgressTrackerFactory( + uploadDetails.progressReporter, request.getContentLength()); long sizePerPart = MultipartUtils.calculatePartSize(uploadConfiguration, request.getContentLength()); @@ -144,9 +162,17 @@ private UploadResponse multipartUpload(UploadRequest uploadDetails) { if (uploadConfiguration.isEnforceMd5BeforeMultipartUpload()) { MD5Calculation md5Calculation = calculateMd5(chunk, chunk.length()); assembler.addPart( - md5Calculation.streamToUse, chunk.length(), md5Calculation.md5); + ProgressTrackingInputStreamFactory.create( + md5Calculation.streamToUse, + progressTrackerFactory.getProgressTracker()), + chunk.length(), + md5Calculation.md5); } else { - assembler.addPart(chunk, chunk.length(), null); + assembler.addPart( + ProgressTrackingInputStreamFactory.create( + chunk, progressTrackerFactory.getProgressTracker()), + chunk.length(), + null); } } CommitMultipartUploadResponse response = assembler.commit(); @@ -287,6 +313,7 @@ public static class UploadRequest { private final PutObjectRequest putObjectRequest; private final ExecutorService parallelUploadExecutorService; private final boolean allowOverwrite; + private final ProgressReporter progressReporter; /** * Creates a new {@link UploadRequestBuilder} using the given stream and content length. The stream and length will @@ -328,6 +355,7 @@ public static class UploadRequestBuilder { // always allow objects to be overwritten unless explicitly disabled private boolean allowOverwrite = true; private ExecutorService parallelUploadExecutorService; + private ProgressReporter progressReporter; /** * Configures whether or not the if-none-match header will be used to prevent @@ -359,6 +387,18 @@ public UploadRequestBuilder parallelUploadExecutorService( return this; } + /** + * Sets the progress reporter that is used to notify of updates during the upload. + * If none is provided, then no progress updates shall be reported. + * + * @param progressReporter The progress reporter to use. + * @return This builder instance + */ + public UploadRequestBuilder progressReporter(ProgressReporter progressReporter) { + this.progressReporter = progressReporter; + return this; + } + /** * Builds a new UploadRequest instance. The body and content length will be set on the given * request based on the original values provided when creating the builder. @@ -376,7 +416,8 @@ public UploadRequest build(PutObjectRequest request) { .ifNoneMatch(ifNoneMatch) .build(), parallelUploadExecutorService, - allowOverwrite); + allowOverwrite, + progressReporter); } } } diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/MultipartObjectAssemblerTest.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/MultipartObjectAssemblerTest.java index c39078227ef..abf3de8a8cf 100644 --- a/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/MultipartObjectAssemblerTest.java +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/MultipartObjectAssemblerTest.java @@ -10,7 +10,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackerTest.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackerTest.java new file mode 100644 index 00000000000..28b5ca48c6a --- /dev/null +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackerTest.java @@ -0,0 +1,318 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.objectstorage.transfer; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.AdditionalMatchers.and; +import static org.mockito.AdditionalMatchers.gt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.AdditionalMatchers.leq; + +import lombok.RequiredArgsConstructor; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +public class ProgressTrackerTest { + private static final long READ_CHUNK_SIZE = 8192L; + private static final long MAX_BLOCK_SIZE = 128 * 1024 * 1024; + private static final long EXECUTION_SERVICE_TIMEOUT_IN_SECONDS = 20; + + @Test + public void nullProgressReporter() { + ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory(null, 0L); + assertNotNull(progressTrackerFactory); + assertNull(progressTrackerFactory.getProgressTracker()); + progressTrackerFactory = + ProgressTrackerFactory.createMultiPartUploadProgressTrackerFactory(null, 0L); + assertNotNull(progressTrackerFactory); + assertNull(progressTrackerFactory.getProgressTracker()); + } + + @Test(expected = IllegalStateException.class) + public void illegalProgressReport_overflow() { + ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + new ProgressReporter() { + @Override + public void onProgress(long completed, long total) {} + }, + 0L); + progressTrackerFactory.getProgressTracker().onBytesRead(READ_CHUNK_SIZE); + } + + @Test(expected = IllegalStateException.class) + public void illegalProgressReport_underflow() { + ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + new ProgressReporter() { + @Override + public void onProgress(long completed, long total) {} + }, + 0L); + progressTrackerFactory.getProgressTracker().onBytesRead(-1); + } + + @Test(expected = IllegalStateException.class) + public void illegalProgressReset() { + ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + new ProgressReporter() { + @Override + public void onProgress(long completed, long total) {} + }, + 0L); + progressTrackerFactory.getProgressTracker().invalidateBytesRead(1); + } + + @Test + public void singleUploadProgressTrackerFactory_sameProgressTracker() { + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + new ProgressReporter() { + @Override + public void onProgress(long completed, long total) {} + }, + 0L); + + assertNotNull(progressTrackerFactory); + assertSame( + progressTrackerFactory.getProgressTracker(), + progressTrackerFactory.getProgressTracker()); + } + + @Test + public void singleUploadProgressTrackerFactory_progressTrackerFunctionality() + throws InterruptedException { + final long totalBytes = ThreadLocalRandom.current().nextLong(MAX_BLOCK_SIZE); + final ProgressReporter mockProgressReporter = mock(ProgressReporter.class); + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + mockProgressReporter, totalBytes); + + int count = trackProgressAndGetCallbackCount(progressTrackerFactory, totalBytes, 1); + verify(mockProgressReporter, times(count)) + .onProgress(and(gt(0L), leq(totalBytes)), eq(totalBytes)); + } + + @Test + public void singleUploadProgressTrackerFactory_resetProgressTracker() { + final long totalBytes = ThreadLocalRandom.current().nextLong(MAX_BLOCK_SIZE); + final ProgressReporter mockProgressReporter = mock(ProgressReporter.class); + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createSingleUploadProgressTrackerFactory( + mockProgressReporter, totalBytes); + final ProgressTracker progressTracker = progressTrackerFactory.getProgressTracker(); + + progressTracker.reset(); + progressTracker.onBytesRead(READ_CHUNK_SIZE); + progressTracker.onBytesRead(READ_CHUNK_SIZE); + progressTracker.reset(); + progressTracker.onBytesRead(READ_CHUNK_SIZE); + progressTracker.onBytesRead(READ_CHUNK_SIZE); + progressTracker.onBytesRead(READ_CHUNK_SIZE); + progressTracker.onBytesRead(READ_CHUNK_SIZE); + progressTracker.reset(); + progressTracker.reset(); + + ArgumentCaptor bytesReadArgumentCaptor = ArgumentCaptor.forClass(Long.class); + verify(mockProgressReporter, times(6)) + .onProgress(bytesReadArgumentCaptor.capture(), eq(totalBytes)); + + List expectedBytesReadList = + Arrays.asList( + READ_CHUNK_SIZE, + 2 * READ_CHUNK_SIZE, + READ_CHUNK_SIZE, + 2 * READ_CHUNK_SIZE, + 3 * READ_CHUNK_SIZE, + 4 * READ_CHUNK_SIZE); + assertEquals(expectedBytesReadList, bytesReadArgumentCaptor.getAllValues()); + } + + @Test + public void multipartUploadProgressTrackerFactory_differentProgressTracker() { + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createMultiPartUploadProgressTrackerFactory( + new ProgressReporter() { + @Override + public void onProgress(long completed, long total) {} + }, + 0L); + + assertNotNull(progressTrackerFactory); + assertNotEquals( + progressTrackerFactory.getProgressTracker(), + progressTrackerFactory.getProgressTracker()); + } + + @Test + public void multipartUploadProgressTrackerFactory_progressTrackerFunctionality() + throws InterruptedException { + final long totalBytes = ThreadLocalRandom.current().nextLong(MAX_BLOCK_SIZE); + final ProgressReporter mockProgressReporter = mock(ProgressReporter.class); + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createMultiPartUploadProgressTrackerFactory( + mockProgressReporter, totalBytes); + + final int invocationCount = + trackProgressAndGetCallbackCount(progressTrackerFactory, totalBytes, 30); + + verify(mockProgressReporter, times(invocationCount)) + .onProgress(and(gt(0L), leq(totalBytes)), eq(totalBytes)); + } + + @Test + public void multipartUploadProgressTrackerFactory_resetProgressTracker() { + final long totalBytes = ThreadLocalRandom.current().nextLong(MAX_BLOCK_SIZE); + final ProgressReporter mockProgressReporter = mock(ProgressReporter.class); + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createMultiPartUploadProgressTrackerFactory( + mockProgressReporter, totalBytes); + final ProgressTracker progressTracker1 = progressTrackerFactory.getProgressTracker(); + final ProgressTracker progressTracker2 = progressTrackerFactory.getProgressTracker(); + + progressTracker1.onBytesRead(READ_CHUNK_SIZE); + progressTracker1.reset(); + progressTracker2.reset(); + progressTracker2.onBytesRead(READ_CHUNK_SIZE); + progressTracker1.onBytesRead(READ_CHUNK_SIZE); + progressTracker2.onBytesRead(READ_CHUNK_SIZE); + progressTracker1.reset(); + progressTracker1.onBytesRead(READ_CHUNK_SIZE); + progressTracker2.reset(); + progressTracker1.reset(); + progressTracker1.reset(); + progressTracker1.onBytesRead(READ_CHUNK_SIZE); + + ArgumentCaptor bytesReadArgumentCaptor = ArgumentCaptor.forClass(Long.class); + verify(mockProgressReporter, times(6)) + .onProgress(bytesReadArgumentCaptor.capture(), eq(totalBytes)); + + List expectedBytesReadList = + Arrays.asList( + READ_CHUNK_SIZE, + READ_CHUNK_SIZE, + 2 * READ_CHUNK_SIZE, + 3 * READ_CHUNK_SIZE, + 3 * READ_CHUNK_SIZE, + READ_CHUNK_SIZE); + assertEquals(expectedBytesReadList, bytesReadArgumentCaptor.getAllValues()); + } + + @Test + public void multipartUploadProgressTrackerFactory_simulateRealLifeScenario() + throws InterruptedException { + final long totalBytes = Long.MAX_VALUE; + final ProgressReporter mockProgressReporter = mock(ProgressReporter.class); + final ProgressTrackerFactory progressTrackerFactory = + ProgressTrackerFactory.createMultiPartUploadProgressTrackerFactory( + mockProgressReporter, totalBytes); + + final List expectedBytesReadList = + Collections.synchronizedList(new ArrayList()); + final AtomicLong totalBytesRead = new AtomicLong(); + final int THREAD_POOL_SIZE = 3; + final int NUMBER_OF_CHUNKS = 10; + final int SIZE_OF_CHUNK = 128 * 1024 * 1024; // 128 MB + final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + + for (int i = 0; i < NUMBER_OF_CHUNKS; i++) { + executorService.submit( + new Runnable() { + final ProgressTracker progressTracker = + progressTrackerFactory.getProgressTracker(); + + @Override + public void run() { + long expectedBytesRead = 0; + for (int i = 0; i < SIZE_OF_CHUNK / READ_CHUNK_SIZE; i++) { + int diceRoll = ThreadLocalRandom.current().nextInt(); + synchronized (expectedBytesReadList) { + if (diceRoll % 10 == 0) { + progressTracker.reset(); + totalBytesRead.addAndGet(-1 * expectedBytesRead); + expectedBytesRead = 0; + } else { + progressTracker.onBytesRead(READ_CHUNK_SIZE); + expectedBytesRead += READ_CHUNK_SIZE; + expectedBytesReadList.add( + totalBytesRead.addAndGet(READ_CHUNK_SIZE)); + } + } + } + } + }); + } + + executorService.shutdown(); + executorService.awaitTermination(EXECUTION_SERVICE_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + + ArgumentCaptor bytesReadArgumentCaptor = ArgumentCaptor.forClass(Long.class); + verify(mockProgressReporter, times(expectedBytesReadList.size())) + .onProgress(bytesReadArgumentCaptor.capture(), eq(totalBytes)); + + assertEquals(expectedBytesReadList, bytesReadArgumentCaptor.getAllValues()); + } + + private static int trackProgressAndGetCallbackCount( + final ProgressTrackerFactory progressTrackerFactory, + final long totalBytes, + final int executorCount) + throws InterruptedException { + final AtomicInteger callbackCount = new AtomicInteger(); + final ExecutorService executorService = Executors.newCachedThreadPool(); + + @RequiredArgsConstructor + abstract class MockProgressTrackerSource implements Runnable { + final ProgressTracker progressTracker; + final long totalBytesToRead; + } + + for (int i = 0; i < executorCount; i++) { + executorService.submit( + new MockProgressTrackerSource( + progressTrackerFactory.getProgressTracker(), + (i == executorCount - 1) + ? totalBytes / executorCount + totalBytes % executorCount + : totalBytes / executorCount) { + @Override + public void run() { + long totalBytesRead = 0; + while (totalBytesRead < totalBytesToRead) { + final long bytesRead = + Math.min( + READ_CHUNK_SIZE, totalBytesToRead - totalBytesRead); + totalBytesRead += bytesRead; + callbackCount.getAndIncrement(); + progressTracker.onBytesRead(bytesRead); + } + } + }); + } + + executorService.shutdown(); + executorService.awaitTermination(EXECUTION_SERVICE_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + + return callbackCount.get(); + } +} diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackingInputStreamTest.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackingInputStreamTest.java new file mode 100644 index 00000000000..8085a741d19 --- /dev/null +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/ProgressTrackingInputStreamTest.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + */ +package com.oracle.bmc.objectstorage.transfer; + +import com.oracle.bmc.io.DuplicatableInputStream; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mockito; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.only; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.InputStream; + +public class ProgressTrackingInputStreamTest { + abstract class DIStream extends InputStream implements DuplicatableInputStream {} + + private static final InputStream inputStream = mock(InputStream.class); + private static final ProgressTracker progressTracker = mock(ProgressTracker.class); + private static final DIStream diStream = mock(DIStream.class); + private static final int READ_CHUNK_SIZE = 8192; + + @Test + public void nullProgressTracker() { + final InputStream progressTrackingInputStream = + ProgressTrackingInputStreamFactory.create(inputStream, null); + + assertSame(inputStream, progressTrackingInputStream); + } + + @Test + public void nonDuplicatableStream() { + final InputStream progressTrackingInputStream = + ProgressTrackingInputStreamFactory.create(inputStream, progressTracker); + + assertFalse(progressTrackingInputStream instanceof DuplicatableInputStream); + } + + @Test + public void duplicatableStream() { + final InputStream progressTrackingInputStream = + ProgressTrackingInputStreamFactory.create(diStream, progressTracker); + + assertTrue(progressTrackingInputStream instanceof DuplicatableInputStream); + } + + @Test + public void duplicatableStream_duplicate() { + final InputStream progressTrackingInputStream = + ProgressTrackingInputStreamFactory.create(diStream, progressTracker); + doReturn(diStream).when(diStream).duplicate(); + + assertTrue(progressTrackingInputStream instanceof DuplicatableInputStream); + final DuplicatableInputStream duplicatableProgressTrackingInputStream = + (DuplicatableInputStream) progressTrackingInputStream; + + final InputStream duplicateStream = duplicatableProgressTrackingInputStream.duplicate(); + assertNotNull(duplicateStream); + assertTrue(duplicateStream instanceof DuplicatableInputStream); + + verify(progressTracker, only()).reset(); + } + + @Test + public void duplicatableStream_readAndDuplicate() throws IOException { + final ProgressTracker progressTracker = mock(ProgressTracker.class); + final InputStream progressTrackingInputStream = + ProgressTrackingInputStreamFactory.create(diStream, progressTracker); + when(diStream.read(any(byte[].class))).thenReturn(READ_CHUNK_SIZE); + when(diStream.read()).thenReturn(1); + doReturn(diStream).when(diStream).duplicate(); + + final InOrder inOrder = Mockito.inOrder(progressTracker); + final byte[] buffer = new byte[READ_CHUNK_SIZE]; + assertEquals(READ_CHUNK_SIZE, progressTrackingInputStream.read(buffer)); + inOrder.verify(progressTracker).onBytesRead(eq((long) READ_CHUNK_SIZE)); + + doReturn(progressTracker).when(progressTracker).reset(); + final InputStream duplicateStream = + ((DuplicatableInputStream) progressTrackingInputStream).duplicate(); + inOrder.verify(progressTracker).reset(); + + assertEquals(1, duplicateStream.read()); + inOrder.verify(progressTracker).onBytesRead(eq(1L)); + assertEquals(READ_CHUNK_SIZE, duplicateStream.read(buffer)); + inOrder.verify(progressTracker).onBytesRead(eq((long) READ_CHUNK_SIZE)); + } +} diff --git a/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/UploadManagerTest.java b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/UploadManagerTest.java index 9a6258f92bf..9af9ccd861d 100644 --- a/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/UploadManagerTest.java +++ b/bmc-objectstorage/bmc-objectstorage-extensions/src/test/java/com/oracle/bmc/objectstorage/transfer/UploadManagerTest.java @@ -7,18 +7,35 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.AdditionalMatchers.and; +import static org.mockito.AdditionalMatchers.gt; +import static org.mockito.AdditionalMatchers.leq; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; - +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; + +import com.oracle.bmc.objectstorage.model.MultipartUpload; +import com.oracle.bmc.objectstorage.requests.CommitMultipartUploadRequest; +import com.oracle.bmc.objectstorage.requests.CreateMultipartUploadRequest; +import com.oracle.bmc.objectstorage.requests.UploadPartRequest; +import com.oracle.bmc.objectstorage.responses.CreateMultipartUploadResponse; +import com.oracle.bmc.objectstorage.responses.UploadPartResponse; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -35,10 +52,13 @@ import com.oracle.bmc.objectstorage.transfer.UploadManager.UploadResponse; import com.oracle.bmc.objectstorage.transfer.internal.MultipartManifestImpl; import com.oracle.bmc.util.StreamUtils; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; public class UploadManagerTest { private static final String CONTENT = Strings.repeat("a", 2097152); // 2MiB private static final long CONTENT_LENGTH = CONTENT.length(); + private static final int READ_BLOCK_SIZE = 8192; // 8KB private static final String CLIENT_REQ_ID = "clientReqId"; private static final String REQ_ID = "reqId"; private static final String CONTENT_TYPE = "application/text"; @@ -59,7 +79,7 @@ public void setUp() { } @Test - public void upload_singleUpload() { + public void upload_singleUpload() throws IOException { UploadConfiguration uploadConfiguration = UploadConfiguration.builder().allowMultipartUploads(false).build(); UploadManager uploadManager = new UploadManager(objectStorage, uploadConfiguration); @@ -84,7 +104,9 @@ public void upload_singleUpload() { assertNull(uploadResponse.getMultipartMd5()); assertEquals(REQ_ID, uploadResponse.getOpcRequestId()); assertEquals(CLIENT_REQ_ID, uploadResponse.getOpcClientRequestId()); - assertSame(body, putRequestCaptor.getValue().getPutObjectBody()); + byte[] buffer = new byte[(int) CONTENT_LENGTH]; + putRequestCaptor.getValue().getPutObjectBody().read(buffer); + assertEquals(CONTENT, new String(buffer)); assertEquals(CONTENT_LENGTH, putRequestCaptor.getValue().getContentLength().longValue()); assertEquals(CLIENT_REQ_ID, putRequestCaptor.getValue().getOpcClientRequestId()); assertSame(METADATA, putRequestCaptor.getValue().getOpcMeta()); @@ -105,7 +127,6 @@ public void upload_singleUpload_enforceMd5() throws Exception { UploadResponse uploadResponse = uploadManager.upload(request); assertNotNull(uploadResponse); - assertSame(body, putRequestCaptor.getValue().getPutObjectBody()); byte[] buffer = new byte[(int) CONTENT_LENGTH]; putRequestCaptor.getValue().getPutObjectBody().read(buffer); assertEquals(CONTENT, new String(buffer)); @@ -313,7 +334,142 @@ protected MultipartObjectAssembler createAssembler( } } - private UploadRequest createUploadRequest() { + @Test + public void singleUpload_progressReporter() throws IOException { + final UploadConfiguration uploadConfiguration = + UploadConfiguration.builder().allowMultipartUploads(false).build(); + final UploadManager uploadManager = new UploadManager(objectStorage, uploadConfiguration); + + final AtomicInteger expectedProgressNotificationCount = new AtomicInteger(); + when(objectStorage.putObject(any(PutObjectRequest.class))) + .then( + new Answer() { + @Override + public PutObjectResponse answer(InvocationOnMock invocationOnMock) + throws Throwable { + final PutObjectRequest putObjectRequest = + invocationOnMock.getArgumentAt(0, null); + final InputStream inputStream = putObjectRequest.getPutObjectBody(); + byte[] buffer = new byte[READ_BLOCK_SIZE]; + while (inputStream.read(buffer) != -1) { + expectedProgressNotificationCount.getAndIncrement(); + } + return PutObjectResponse.builder().build(); + } + }); + + final ProgressReporter progressReporter = mock(ProgressReporter.class); + final UploadResponse uploadResponse = + uploadManager.upload(createUploadRequest(progressReporter)); + assertNotNull(uploadResponse); + verify(progressReporter, times(expectedProgressNotificationCount.get())) + .onProgress(and(gt(0L), leq(CONTENT_LENGTH)), eq(CONTENT_LENGTH)); + } + + @Test + public void multipartUpload_progressReporter() { + final UploadManager uploadManager = + new UploadManager(objectStorage, getMultipartUploadConfiguration()) { + @Override + protected MultipartObjectAssembler createAssembler( + PutObjectRequest request, + UploadRequest uploadRequest, + ExecutorService executorService) { + return assembler; + } + }; + + final AtomicInteger onProgressCallbackCount = new AtomicInteger(); + when(assembler.addPart(any(InputStream.class), anyLong(), anyString())) + .thenAnswer( + new Answer() { + @Override + public Integer answer(InvocationOnMock invocationOnMock) + throws Throwable { + final InputStream inputStream = invocationOnMock.getArgumentAt(0, null); + final byte[] buffer = new byte[READ_BLOCK_SIZE]; + while (inputStream.read(buffer) != -1) { + onProgressCallbackCount.incrementAndGet(); + } + return ThreadLocalRandom.current().nextInt(); + } + }); + when(assembler.commit()).thenReturn(CommitMultipartUploadResponse.builder().build()); + + final ProgressReporter progressReporter = mock(ProgressReporter.class); + final UploadResponse uploadResponse = + uploadManager.upload(createUploadRequest(progressReporter)); + assertNotNull(uploadResponse); + + verify(progressReporter, times(onProgressCallbackCount.get())) + .onProgress(and(gt(0L), leq(CONTENT_LENGTH)), eq(CONTENT_LENGTH)); + } + + @Test + public void multipartUpload_progressReporter_withRetries() { + final UploadManager uploadManager = + new UploadManager(objectStorage, getMultipartUploadConfiguration()); + + when(objectStorage.createMultipartUpload(any(CreateMultipartUploadRequest.class))) + .thenReturn( + CreateMultipartUploadResponse.builder() + .multipartUpload(MultipartUpload.builder().build()) + .build()); + final AtomicInteger onProgressCallbackCount = new AtomicInteger(); + final ConcurrentMap retryCountMap = new ConcurrentHashMap<>(); + when(objectStorage.uploadPart(any(UploadPartRequest.class))) + .thenAnswer( + new Answer() { + @Override + public UploadPartResponse answer(InvocationOnMock invocationOnMock) + throws Throwable { + final UploadPartRequest uploadPartRequest = + invocationOnMock.getArgumentAt(0, null); + final int uploadPartNum = uploadPartRequest.getUploadPartNum(); + final InputStream inputStream = + uploadPartRequest.getUploadPartBody(); + final byte[] buffer = new byte[READ_BLOCK_SIZE]; + while (inputStream.read(buffer) != -1) { + onProgressCallbackCount.incrementAndGet(); + + if (!retryCountMap.containsKey(uploadPartNum)) { + retryCountMap.put(uploadPartNum, 0); + } + final int retryCount = retryCountMap.get(uploadPartNum); + final boolean shouldTriggerRetry = + ThreadLocalRandom.current().nextBoolean() + && retryCount < 2 + && retryCountMap.replace( + uploadPartNum, + retryCount, + retryCount + 1); + if (shouldTriggerRetry) { + throw new BmcException(-1, null, null, null); + } + } + return UploadPartResponse.builder().build(); + } + }); + when(objectStorage.commitMultipartUpload(any(CommitMultipartUploadRequest.class))) + .thenReturn(CommitMultipartUploadResponse.builder().build()); + + final ProgressReporter progressReporter = mock(ProgressReporter.class); + final UploadResponse uploadResponse = + uploadManager.upload(createUploadRequest(progressReporter)); + assertNotNull(uploadResponse); + + verify(progressReporter, times(onProgressCallbackCount.get())) + .onProgress(and(gt(0L), leq(CONTENT_LENGTH)), eq(CONTENT_LENGTH)); + } + + private static UploadConfiguration getMultipartUploadConfiguration() { + return UploadConfiguration.builder() + .minimumLengthForMultipartUpload(0) + .minimumLengthPerUploadPart(1) + .build(); + } + + private UploadRequest createUploadRequest(ProgressReporter progressReporter) { PutObjectRequest request = PutObjectRequest.builder() .opcMeta(METADATA) @@ -322,6 +478,12 @@ private UploadRequest createUploadRequest() { .contentType(CONTENT_TYPE) .contentEncoding(CONTENT_ENCODING) .build(); - return UploadRequest.builder(body, CONTENT_LENGTH).build(request); + return UploadRequest.builder(body, CONTENT_LENGTH) + .progressReporter(progressReporter) + .build(request); + } + + private UploadRequest createUploadRequest() { + return createUploadRequest(null); } } diff --git a/bmc-objectstorage/bmc-objectstorage-generated/pom.xml b/bmc-objectstorage/bmc-objectstorage-generated/pom.xml index eb8ffe5cb68..2565e7f12e7 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 - 1.2.41 + 1.2.42 ../../pom.xml @@ -18,7 +18,7 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 diff --git a/bmc-objectstorage/pom.xml b/bmc-objectstorage/pom.xml index 3d4dec2efdb..eaf64ded3ca 100644 --- a/bmc-objectstorage/pom.xml +++ b/bmc-objectstorage/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml @@ -19,17 +19,17 @@ com.oracle.oci.sdk oci-java-sdk-common - 1.2.41 + 1.2.42 com.oracle.oci.sdk oci-java-sdk-objectstorage-generated - 1.2.41 + 1.2.42 com.oracle.oci.sdk oci-java-sdk-objectstorage-extensions - 1.2.41 + 1.2.42 diff --git a/bmc-shaded/bmc-shaded-full/pom.xml b/bmc-shaded/bmc-shaded-full/pom.xml index 1fd6e72545c..d24b1c7ee3e 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.2.41 + 1.2.42 ../pom.xml oci-java-sdk-shaded-full diff --git a/bmc-shaded/pom.xml b/bmc-shaded/pom.xml index f569ed0d729..0bfbd427ced 100644 --- a/bmc-shaded/pom.xml +++ b/bmc-shaded/pom.xml @@ -5,7 +5,7 @@ com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 ../pom.xml diff --git a/pom.xml b/pom.xml index 2f4a9180e8a..3f75beb005b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.oracle.oci.sdk oci-java-sdk - 1.2.41 + 1.2.42 pom Oracle Cloud Infrastructure SDK This project contains the SDK used for Oracle Cloud Infrastructure @@ -41,6 +41,8 @@ a breaking change. http://bouncy-castle.1462172.n4.nabble.com/Issues-when-migrating-to-1-53-td4657955.html https://github.com/box/box-java-sdk/issues/168 Has not been fixed as of 1.55. --> 1.52 + 1.10.19 + 1.7.4 **/*IntegrationAutoTest.java @@ -376,7 +378,19 @@ org.mockito mockito-core - 2.15.0 + ${mockito.version} + test + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + org.powermock + powermock-api-mockito + ${powermock.version} test