Conceptos

En este tema se explican algunos de los conceptos clave para utilizar el SDK para Java de Oracle Cloud Infrastructure.

En este tema se explican algunos de los conceptos clave para utilizar el SDK para Java de Oracle Cloud Infrastructure.

Llamadas síncronas

Para realizar llamadas síncronas, cree una instancia del cliente síncrono. El patrón general para los clientes síncronos es que, para un servicio denominado Example, habrá una interfaz denominada ExampleService, y la implantación de cliente síncrono se llamará ExampleServiceClient. A continuación se muestra un ejemplo de creación de un cliente de Object Storage:

AuthenticationDetailsProvider provider = ...;
ObjectStorage clientWithDefaultClientConfig = new ObjectStorageClient(provider);
clientWithDefaultClientConfig.setRegion(Region.US_ASHBURN_1);

ClientConfiguration clientConfig = ...;
ObjectStorage clientWithExplicitClientConfig = new ObjectStorageClient(provider, clientConfig);
clientWithExplicitClientConfig.setRegion(Region.US_ASHBURN_1);

Las llamadas síncronas se bloquearán hasta que la respuesta esté disponible. Todas las API de SDK devuelven un objeto de respuesta (independientemente de si la API devuelve o no contenido). El objeto de respuesta suele contener al menos un ID de solicitud que puede utilizar al contactar con los Servicios de soporte Oracle para obtener ayuda sobre una solicitud concreta.

ObjectStorage client = ...;
GetBucketResponse response = client.getBucket(
    GetBucketRequest.builder().namespaceName("myNamespace").bucketName("myBucket").build());
String requestId = response.getOpcRequestId();
Bucket bucket = response.getBucket();
System.out.println(requestId);
System.out.println(bucket.getName());

Llamadas asíncronas

Para realizar llamadas asíncronas, cree una instancia del cliente asíncrono. El patrón general para los clientes asíncronos es que, para un servicio denominado Example, habrá una interfaz denominada ExampleServiceAsync, y la implantación de cliente asíncrono se llamará ExampleServiceAsyncClient. A continuación se muestra un ejemplo de creación de un cliente de Object Storage:

AuthenticationDetailsProvider provider = ...;
ObjectStorageAsync clientWithDefaultClientConfig = new ObjectStorageAsyncClient(provider);
clientWithDefaultClientConfig.setRegion(Region.US_ASHBURN_1);
 
ClientConfiguration clientConfig = ...;
ObjectStorageAsync clientWithExplicitClientConfig = new ObjectStorageAsyncClient(provider, clientConfig);
clientWithExplicitClientConfig.setRegion(Region.US_ASHBURN_1);

Las llamadas asíncronas se devuelven inmediatamente. Debe proporcionar un AsyncHandler al que se llamará después de que la llamada termine correctamente o de forma incorrecta:

ObjectStorageAsync client = ...;
 
AsyncHandler<GetBucketRequest, GetBucketResponse> handler = new AsyncHandler<GetBucketRequest, GetBucketResponse>() {
        @Override
        public void onSuccess(GetBucketRequest request, GetBucketResponse response) {
            String requestId = response.getOpcRequestId();
            Bucket bucket = response.getBucket();
            System.out.println(requestId);
            System.out.println(bucket.getName());
        }

        @Override
        public void onError(GetBucketRequest request, Throwable error) {
            error.printStackTrace();
        }
};
 
Future<GetBucketResponse> future = client.getBucket(
        GetBucketRequest.builder().namespaceName("myNamespace").bucketName("myBucket").build(),
        handler);

Sondeo con procesos en espera

El SDK ofrece procesos en espera que permiten que el código espere hasta que un recurso específico alcance el estado deseado. Se puede llamar a un proceso en espera en modo de bloqueo o no bloqueo (con devolución de llamada asíncrona) y este esperará hasta que se alcance el estado deseado o se exceda el tiempo de espera. Los procesos en espera sintetizan la lógica de sondeo que, de lo contrario, tendría que escribir en una llamada de método único fácil de utilizar.

Los procesos en espera se obtienen mediante el cliente de servicio (client.getWaiters()). Tanto Get<Resource>Request como el estado de ciclo de vida deseado se transfieren al método waiters.for<Resource>. Por ejemplo:

public static Instance waitForInstanceProvisioningToComplete(  ComputeClient computeClient, String instanceId) throws Exception {
        
    ComputeWaiters waiters = computeClient.getWaiters();
    GetInstanceResponse response = waiters.forInstance(
        GetInstanceRequest.builder().instanceId(instanceId).build(),
        Instance.LifecycleState.Running)
    .execute();
        
    return response.getInstance();
}

Cada método waiters.for<Resource> tiene dos versiones:

  • Una versión utiliza los valores de sondeo por defecto. Por ejemplo:

    waiters.forInstance(GetInstanceRequest, LifecycleState)
  • La otra versión proporciona el control total sobre el tiempo de espera y el tiempo entre intentos de sondeo. Por ejemplo:

    waiters.forInstance(GetInstanceRequest, LifecycleState, TerminationStrategy, DelayStrategy)

Modelo de thread

Un cliente se convierte en seguro para el thread cuando se inicializa. Después de definir su punto final, puede utilizar en él de forma segura un cliente en varios threads y métodos de llamada simultáneamente.

Puede volver a utilizar un cliente en varias solicitudes, en threads simultáneos o en un único thread. A menos que se restrinjan los recursos del entorno, solo debe cerrar el cliente inmediatamente antes de que salga del ámbito.

Nota

Esta garantía solo se aplica a la implantación de JAX-RS por defecto, Jersey. Al utilizar una implantación alternativa, debe gestionar la seguridad del thread usted mismo. Para obtener más información, consulte Configuración del SDK

Carga de objetos grandes

El servicio Object Storage soporta cargas de varias partes para facilitar las cargas de objetos grandes mediante la división del objeto grande en partes. El SDK para Java soporta operaciones de carga de varias partes raw para casos de uso avanzados, así como una clase de carga de nivel superior que utiliza las API de carga de varias partes. El uso de cargas de varias partes proporciona enlaces a las API utilizadas para operaciones de carga de varias partes. Las cargas de varias partes de nivel superior se implantan con UploadManager, que: dividirá un objeto grande en partes, cargará las partes en paralelo y, a continuación, volverá a combinar y confirmar las partes como un único objeto en el almacenamiento.

El ejemplo UploadObject muestra cómo utilizar UploadManager para dividir automáticamente un objeto en partes y cargarlo para simplificar la interacción con el servicio Object Storage.

Reintentos

A partir de la versión 2.10.0, el SDK para Java está configurado por defecto para reintentar determinadas operaciones de SDK que fallan. El SDK permite especificar la estrategia que se desea utilizar para el manejo de los reintentos, incluido el número de veces que se debe realizar un reintento, la condición en la que el SDK debe reintentar una operación y cuándo dejar de reintentar una operación. Puede definir estos parámetros en el nivel de cliente y en el nivel de solicitud individual.

Para determinar qué operaciones de servicio tienen reintentos activados por defecto, consulte la descripción de las operaciones de servicio en el SDK.

Nota

Los reintentos no están soportados actualmente para los clientes asíncronos

Por defecto, el SDK reintentará las operaciones de los códigos de estado de respuesta HTTP 409 (con un código de error IncorrectState), 429, 500, 502, 503, 504, errores de timeout (como conexiones HTTP y timeouts de lectura), errores de conexión de solicitud, excepciones de solicitud y excepciones de disyuntor.

La configuración de reintento por defecto más reciente y la lista de errores que se pueden reintentar se pueden ver en Github.

Desactivación de reintentos por defecto

Para excluirse de la función de reintentos por defecto, puede realizar una de las siguientes acciones:

  1. Definir la variable de entorno OCI_SDK_DEFAULT_RETRY_ENABLED en false para desactivar los reintentos por defecto de forma global
  2. Sustituir los reintentos por defecto para una instancia de cliente concreta. En este ejemplo, se muestra la sustitución de los reintentos por defecto para objectStorageClient:

    ClientConfiguration clientConfiguration =
            ClientConfiguration.builder()
                    .retryConfiguration(RetryConfiguration.builder().terminationStrategy(new MaxAttemptsTerminationStrategy(1))
                            .build())
                    .build();
    ObjectStorage objectStorageClient = ObjectStorageClient.builder().configuration(clientConfiguration).build(provider);
    
  3. Sustituir reintentos por defecto para una instancia de solicitud concreta. En este ejemplo, se muestran los reintentos de sustitución para putObjectRequest:

    PutObjectRequest putObjectRequest =
            PutObjectRequest.builder()
                    .putObjectBody(stream)
                    .bucketName(bucketName)
                    .objectName(objectName)
                    .namespaceName(namespace)
                    .retryConfiguration(RetryConfiguration.builder().terminationStrategy(new MaxAttemptsTerminationStrategy(1)).build())
                    .build();

Prioridad del comportamiento de los reintentos

  • Cualquier configuración de reintento que defina explícitamente en el nivel de solicitud sustituirá la configuración de reintento de nivel de cliente o la configuración de reintento de nivel global, así como la sustitución de variable de entorno para esa instancia de solicitud específica.
  • Cualquier configuración de reintento definida explícitamente en el nivel de cliente sustituirá la configuración de reintento global y la sustitución de nivel de variable de entorno para esa instancia de cliente en particular.

Estrategias de reintentos

Puede especificar la estrategia que se va a utilizar para el manejo de los reintentos, incluido el número de veces que se debe realizar un reintento, la condición en la que el SDK debe volver a intentar una operación y cuándo dejar de reintentar una operación. Puede definir estos parámetros en el nivel de cliente y en el nivel de solicitud individual.
Nota

La configuración de reintento por defecto más reciente y la lista de errores que se pueden reintentar se pueden ver en Github.

Estrategia de retraso

El parámetro delayStrategy determina el tiempo que se debe esperar entre cada llamada de reintento. Hay dos opciones para este parámetro:

  • FixedTimeDelayStrategy (milliseconds): cada reintento se retrasa en un número especificado de milisegundos.
  • ExponentialBackoffDelayStrategy (milliseconds): el tiempo de retraso de las llamadas de reintento posteriores aumenta en un factor exponencial de 2 hasta que alcanza el retraso máximo definido (en milisegundos), con un valor base de un milisegundo.

La estrategia de retraso por defecto se define en ExponentialBackoffDelayStrategy con un valor de jitter entre 0 y 1000 milisegundos y un tiempo de espera máximo entre llamadas de 30 segundos.

Condición de reintento

retryCondition define una función con un argumento de error que devuelve un booleano que indica si se desea reintentar o no. La operación se reintentará si esta función devuelve true.

Estrategia de terminación

El parámetro terminationStrategy define cuándo terminar los reintentos. Este parámetro soporta las siguientes opciones:

  • MaxTimeTerminationStrategy (milliseconds): define la duración total en milisegundos durante la cual se realizan los reintentos.
  • MaxAttemptsTerminationStrategy (attempts): define el número total de reintentos.

La estrategia de terminación por defecto para los SDK de OCI es MaxAttemptsTerminationStrategy de 8.

Ejemplos de reintentos

Java

En este ejemplo se muestra cómo configurar y utilizar los reintentos con el SDK para Java:

/**
 * Copyright (c) 2016, 2021, Oracle and/or its affiliates.  All rights reserved.
 * This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
 */
import com.oracle.bmc.ClientConfiguration;
import com.oracle.bmc.ConfigFileReader;
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import com.oracle.bmc.identity.Identity;
import com.oracle.bmc.identity.IdentityClient;
import com.oracle.bmc.identity.requests.ListRegionsRequest;
import com.oracle.bmc.identity.responses.ListRegionsResponse;
import com.oracle.bmc.retrier.Retriers;
import com.oracle.bmc.retrier.RetryConfiguration;
import com.oracle.bmc.waiter.FixedTimeDelayStrategy;
import com.oracle.bmc.waiter.MaxAttemptsTerminationStrategy;

/**
 * This example demonstrates how to use the SDK retries.
 *
 * Retry configuration may be set at
 * a) the SDK level (using {@link Retriers#setDefaultRetryConfiguration(RetryConfiguration)}
 * b) the client level (using {@link ClientConfiguration}
 * c) the request level (using {@link com.oracle.bmc.requests.BmcRequest#setRetryConfiguration(RetryConfiguration)}
 */
public class RetryExample {
    public static void main(String[] args) throws Exception {
        String configurationFilePath = "~/.oci/config";
        String profile = "DEFAULT";

        // Configuring the AuthenticationDetailsProvider. It's assuming there is a default OCI config file
        // "~/.oci/config", and a profile in that config with the name "DEFAULT". Make changes to the following
        // line if needed and use ConfigFileReader.parse(configurationFilePath, profile);

        final ConfigFileReader.ConfigFile configFile = ConfigFileReader.parseDefault();

        final AuthenticationDetailsProvider provider =
                new ConfigFileAuthenticationDetailsProvider(configFile);

        // Set the default retry strategy for all operations to set retry attempts to 3
        Retriers.setDefaultRetryConfiguration(
                RetryConfiguration.builder()
                        .terminationStrategy(new MaxAttemptsTerminationStrategy(3))
                        .build());

        // Override the default retry strategy for the identity client and update retry attempts to 4
        final Identity identityClient =
                new IdentityClient(
                        provider,
                        ClientConfiguration.builder()
                                .retryConfiguration(
                                        RetryConfiguration.builder()
                                                .terminationStrategy(
                                                        new MaxAttemptsTerminationStrategy(4))
                                                .build())
                                .build());

        // Override the client's retry strategy for the list regions request and wait for 5ms between retrying
        final ListRegionsRequest listRegionsRequest =
                ListRegionsRequest.builder()
                        .retryConfiguration(
                                RetryConfiguration.builder()
                                        .terminationStrategy(new MaxAttemptsTerminationStrategy(2))
                                        .delayStrategy(new FixedTimeDelayStrategy(5L))
                                        .build())
                        .build();
        final ListRegionsResponse listRegionsResponse =
                identityClient.listRegions(listRegionsRequest);

        System.out.println(listRegionsResponse.getItems());
    }
}

Disyuntores

A partir de la versión 2.10.0, el SDK para Java proporciona soporte por defecto para disyuntores para clientes de servicio que han activado disyuntores de SDK por defecto. Los disyuntores ayudan a evitar que el cliente desborde el servicio bloqueando el envío de las solicitudes al servicio después de alcanzar un determinado umbral de fallo.

Nota

Los disyuntores por defecto no están soportados actualmente para los clientes asíncronos.

Para los disyuntores por defecto, todos los errores que se pueden reintentar se tratarán como fallos para los disyuntores. Para determinar qué clientes de servicio tienen los disyuntores activados, consulte la descripción del cliente de servicio en el SDK.

Nota

La configuración de disyuntor por defecto se puede ver en Github.

Configuración de disyuntor

Los siguientes parámetros definen un disyuntor:

  • Umbral de ratio de fallos: el estado del disyuntor cambia de CLOSED a OPEN cuando el ratio de fallos es igual o mayor que este umbral. Por ejemplo, si han fallado más del 50 % de las llamadas registradas, el disyuntor se abrirá.
  • Timeout de restablecimiento: timeout tras el cual un disyuntor abierto intentará una solicitud si se realiza una solicitud
  • Excepciones de fallo: lista de excepciones que se considerarán fallos para el circuito
  • Número mínimo de llamadas/umbral de volumen: número mínimo de llamadas necesarias (por período de ventana deslizante) antes de que el disyuntor pueda calcular el ratio de errores

Configuración por defecto del disyuntor

A continuación se muestra la configuración por defecto del disyuntor:

  • Umbral de ratio de fallos: 80 %. Si falla el 80 % de las solicitudes calculadas para una ventana de tiempo de 120 segundos, el circuito pasará de cerrado a abierto.
  • Número mínimo de llamadas/umbral de volumen: 10 para la ventana de tiempo definida anteriormente de 120 segundos.
  • Timeout de restablecimiento: el disyuntor esperará 30 segundos antes de definir el disyuntor en el estado halfOpen e intentar la acción nuevamente.
  • Excepciones de fallo: los fallos del circuito solo se registrarán para excepciones reintentables o transitorias. Los códigos de respuesta HTTP 409 (con IncorrectState), 429, 500, 502, 503 y 504, las solicitudes HTTP y otros timeouts, los errores de conexión de solicitud y las excepciones se tratan como fallos que dispararán un disyuntor.

Desactivación del disyuntor por defecto

Para excluir la función de disyuntor por defecto, puede realizar una de las siguientes acciones:

  1. Defina la variable de entorno OCI_SDK_DEFAULT_CIRCUITBREAKER_ENABLED en false.
  2. Cambiar la configuración de disyuntor por defecto d para una instancia de cliente. En el siguiente ejemplo se muestra cómo hacerlo con una instancia IdentityClient:
    ClientConfiguration clientConfiguration =
            ClientConfiguration.builder().circuitBreakerConfiguration(CircuitBreakerUtils.getNoCircuitBreakerConfiguration()).build();
     
            // Create Clients using above ClientConfiguration
            IdentityClient identityClient = new IdentityClient(provider, clientConfiguration);

Prioridad del comportamiento del disyuntor

Cualquier configuración de disyuntor que defina explícitamente en el nivel de cliente sustituirá la configuración global de disyuntor por defecto y la sustitución de nivel de entorno para ese cliente.

Para obtener información adicional sobre los disyuntores y la configuración de disyuntor por defecto, consulte este ejemplo en Github.

Solicitudes raw

Las solicitudes raw son útiles y, en algunos casos, son necesarias. Los casos de uso habituales son: al utilizar su propio cliente HTTP, realizando una solicitud con la autenticación de OCI en un punto final alternativo y realizando una solicitud a una API de OCI que no está soportada actualmente en el SDK. SDK para Java expone la clase DefaultRequestSigner que puede utilizar para crear una instancia RequestSigner para solicitudes no estándar.

El ejemplo de solicitud raw de GitHub muestra cómo:

  • crear un proveedor de autenticación y firmante de solicitud
  • integrarse con un cliente HTTP (Jersey en este ejemplo) para autenticar solicitudes

Definición de los puntos finales

Los puntos finales de servicio se pueden definir de tres formas.

  • Llame a setEndpoint() en la instancia de servicio. Esto permitirá especificar un nombre de host completo (por ejemplo, https://www.example.com).
  • Llame a setRegion() en la instancia de servicio. Así se selecciona el nombre de host adecuado para el servicio de la región especificada. Sin embargo, si el servicio no está soportado en la región definida, el SDK de Java devuelve un error.
  • Transfiera la región en el archivo de configuración. Para obtener más información, consulte Archivo de configuración de SDK y CLI.

Tenga en cuenta que una instancia de servicio no se puede utilizar para comunicarse con diferentes regiones. Si necesita realizar solicitudes en distintas regiones, cree varias instancias de servicio.

Puntos finales dedicados

Los puntos finales dedicados son las plantillas de punto final definidas por el servicio para un dominio específico en el nivel de cliente. OCI Java SDK permite activar el uso de la función de plantillas de punto final específicas del dominio tanto en el nivel de aplicación como en el nivel de cliente. Esta función está desactivada por defecto.
Nota

El valor definido en el nivel de cliente tiene prioridad sobre el valor definido en el nivel de aplicación.

Activación de plantillas de punto final específicas de dominio en el nivel de aplicación:

Para activar la función de plantillas de punto final específicas del dominio en el nivel de aplicación, defina la variable de entorno OCI_REALM_SPECIFIC_SERVICE_ENDPOINT_TEMPLATE_ENABLED en true.
Nota

El valor booleano no distingue entre mayúsculas y minúsculas.

Activación de plantillas de punto final específicas de dominio en el nivel de aplicación:

Para activar la función de plantillas de punto final específicas del dominio en el nivel de cliente, defina el indicador en el código como se muestra:

Para el SDK de OCI para Java:

ObjectStorage client = ObjectStorageClient.builder().build(provider);
client.useRealmSpecificEndpointTemplate(true);

Para ver un ejemplo completo, consulte UseRealmSpecificEndpointsExample on Github.

Para el SDK de OCI heredado de Java:

ObjectStorage client = new ObjectStorageClient(provider);
client.useRealmSpecificEndpointTemplate(true);

Para ver un ejemplo completo, consulte UseRealmSpecificEndpointsExample on GitHub.

Compatibilidad con versiones futuras y enumeraciones

Si tiene una lógica condicional basada en una enumeración, asegúrese de que su código maneja el caso de UnknownEnumValue para garantizar la compatibilidad con versiones futuras. Algunos campos de respuesta son del tipo enumeración, pero en el futuro, los servicios individuales pueden devolver valores no cubiertos por las enumeraciones existentes para ese campo. Para abordar esta posibilidad, cada campo de respuesta de tipo enumeración tiene un valor adicional denominado UnknownEnumValue. Si un servicio devuelve un valor que la versión del SDK no reconoce, el campo de respuesta se definirá en este valor.

Nuevo soporte de región

Si está utilizando una versión del SDK lanzado antes del anuncio de una nueva región, puede utilizar una solución alternativa para acceder a ella.

Una región es un área geográfica localizada. Para obtener más información sobre las regiones y cómo identificarlas, consulte Regiones y dominios de disponibilidad.

Un dominio es un juego de regiones que comparten entidades. Puede identificar el dominio consultando el nombre del dominio al final de la dirección de red. Por ejemplo, el dominio para xyz.abc.123.oraclecloud.com es oraclecloud.com.

Primero debe llamar a Region.register para registrar la nueva región y, a continuación, puede definir la región utilizando el archivo de configuración o llamando al método setRegion.

Nota

Una vez registrada una región, ya no se necesita el punto final de federación al utilizar principales de instancia. Para ver un ejemplo, consulte https://github.com/oracle/oci-java-sdk/blob/master/bmc-examples/src/main/java/NewRegionAndRealmSupportWithoutSDKUpdate.java.

Dominio de oraclecloud.com

Para las regiones del dominio oraclecloud.com, puede transferir nuevos nombres de región de la misma forma que pasaría los ya definidos en la enumeración de regiones para su versión de SDK.

Nota

Para los siguientes ejemplos de código, asegúrese de proporcionar los puntos finales adecuados para la región.

Si utiliza la versión 1.2.34 o posterior del SDK para Java, puede transferir el nuevo nombre de región como cadena mediante uno de los siguientes métodos:

  • Para definir la región en un cliente creado anteriormente:

    client.setRegion("ca-toronto-1");
  • Para definir una región al crear un nuevo cliente:

    Identity identityClient = IdentityClient.builder()
            .region("ca-toronto-1")
            .build(provider); 
  • También puede transferir la región en el archivo de configuración. Para obtener más información, consulte Archivo de configuración de SDK y CLI.

Otros dominios

Para las regiones de dominios que no sean oraclecloud.com, puede utilizar las siguientes soluciones alternativas para acceder a nuevas regiones con versiones anteriores del SDK.

Para especificar el punto final:
AuthenticationDetailsProvider provider =
        new ConfigFileAuthenticationDetailsProvider(configurationFilePath, profile);

IdentityClient client = IdentityClient.builder()
        .endpoint("https://identity.ca-toronto-1.oraclecloud.com")
        .build(provider);
Si está autenticando mediante principales de instancia, puede definir el punto final y federationEndpoint mediante el siguiente proceso:
InstancePrincipalsAuthenticationDetailsProvider provider = InstancePrincipalsAuthenticationDetailsProvider.builder()
        .federationEndpoint("https://auth.ca-toronto-1.oraclecloud.com/v1/x509")
        .build();

IdentityClient identityClient = IdentityClient.builder()
        .endpoint("https://identity.ca-toronto-1.oraclecloud.com")
        .build(provider);

Respuestas paginadas

Algunas API devuelven juegos de resultados paginados, por lo que debe comprobar los elementos adicionales y, si es necesario, recuperar la siguiente página. Puede hacerlo de forma manual o puede utilizar un iterador.

Recuperación manual de páginas

Los objetos de respuesta contienen un método para recuperar el siguiente token de página. Si el token es nulo, no hay más elementos. Si no es nulo, puede realizar una solicitud adicional definiendo el token en el objeto Request para obtener la siguiente página de respuestas.

Nota

Algunas API pueden devolver un token incluso aunque no haya resultados adicionales. Asegúrese de comprobar también si se ha devuelto algún elemento y párelo si hay alguno.

En este ejemplo se muestra cómo manejar tokens de página devueltos por la API de Object Storage:

ObjectStorage client = ...;
 
ListBucketsRequest.Builder builder =
    ListBucketsRequest.builder().namespaceName(namespace);
String nextPageToken = null;
do {
    builder.page(nextPageToken);
    ListBucketsResponse listResponse = client.listBuckets(builder.build());
    List<Bucket> buckets = listResponse.getItems();
    // handle buckets
    nextPageToken = listResponse.getOpcNextPage();
} while (nextPageToken != null);

Uso de un iterador

En lugar de trabajar manualmente con tokens de página, puede utilizar un iterador. Cada cliente de servicio expone un método getPaginators() que devuelve un objeto Paginator. Este objeto contiene métodos para devolver objetos del tipo Iterable. Se soportan dos enfoques para utilizar iterables:

  • Iterador de respuesta: puede iterar sobre los objetos Response que devuelve la operación de enumeración. A estos se les conoce como ResponseIterators, y en sus métodos se incluye como sufijo "ResponseIterator", por ejemplo, listUsersResponseIterator.
    Iterable<ListUsersResponse> responseIterator = identityClient.getPaginators().listUsersResponseIterator(request);
    for (ListUsersResponse response : responseIterator) {
        for (User user : response.getItems()) {
            System.out.println(user);
        }
    }
  • Iterador de registro: puede iterar sobre los recursos/registros mostrados. A estos se les conoce como RecordIterator, y en sus métodos se incluye como sufijo "RecordIterator", por ejemplo, listUsersRecordIterator.
    Iterable<User> recordIterator = identityClient.getPaginators().listUsersRecordIterator(request)
    for (User user : recordIterator) {
        System.out.println(user);
    }

Cifrado del cliente

El cifrado del cliente permite cifrar datos en el cliente antes de almacenarlos localmente o utilizarlos con otros servicios de Oracle Cloud Infrastructure.

Para utilizar el cifrado del cliente, debe crear una clave de cifrado maestra (MEK) mediante el servicio de gestión de claves. Esto se puede hacer con las operaciones CreateKey o ImportKey.

La MEK se utiliza para generar una clave de cifrado de datos (DEK) para cifrar cada carga útil. Una copia cifrada de esta DEK (cifrada con la MEK) y otras partes de metadatos se incluyen en la carga útil cifrada devuelta por los SDK a fin de que se puedan utilizar para el descifrado.

Requisitos de Java

Los archivos de política ilimitados para versiones anteriores solo se necesitan para las actualizaciones de JDK 8, 7 y 6 anteriores a 8u161, 7u171 y 6u16. Los archivos de política se incluyen para estas versiones y posteriores, pero no están activados por defecto.

Las versiones actuales de JDK no necesitan estos archivos de política. Se proporcionan aquí para su uso con versiones anteriores de JDK. JDK 9 y versiones posteriores se envían con los archivos de política ilimitados, y los utilizan por defecto.

Ejemplos

En el siguiente ejemplo de código se muestra cómo cifrar una cadena:


// String encryption example
			
final byte[] plainText = "Hello World".getBytes();
String masterKeyId = "OCID....";
Map<String, String> context = Collections.singletonMap("Example", "value");
 
OciCrypto ociCrypto = new OciCrypto();
KmsMasterKey kmsMasterKey = new KmsMasterKey(authenticationProvider, Region.US_ASHBURN_1.getRegionId(), vaultId, masterKeyId);
KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(kmsMasterKey);
 
//  Encrypt the data and embed the master key ID in the header
final OciCryptoResult encryptResult = ociCrypto.encryptData(kmsMasterKeyProvider, plainText, context);
final byte[] cipherText = encryptResult.getResult();
 
//  Decrypt the data
final OciCryptoResult decryptResult = ociCrypto.decryptData(kmsMasterKeyProvider, cipherText);

En el siguiente ejemplo se muestra cómo cifrar un flujo de archivos:


// Create Encryption file stream
FileInputStream in = new FileInputStream(srcFile);
OciCrypto ociCrypto = new OciCrypto();
KmsMasterKey kmsMasterKey = new KmsMasterKey(authenticationProvider, Region.US_ASHBURN_1.getRegionId(), vaultId, masterKeyId);
KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(kmsMasterKey);
OciCryptoInputStream encryptingStream = ociCrypto.createEncryptingStream(kmsMasterKeyProvider, in);
 
// Write the encrypted data to file
FileOutputStream out = new FileOutputStream(srcFile + ".encrypted");
IOUtils.copy(encryptingStream, out);
encryptingStream.close();
out.close();
 
// For decryption, no need to pass key info
KmsMasterKeyProvider kmsMasterKeyProvider = new KmsMasterKeyProvider(authenticationProvider);
// Create the Decryption file stream.
in = new FileInputStream(srcFile + ".encrypted");
OciCryptoInputStream decryptingStream = ociCrypto.createDecryptingStream(kmsMasterKeyProvider, in);
 
 
// Return the plaintext data
out = new FileOutputStream(srcFile + ".decrypted");
IOUtils.copy(decryptingStream, out);
decryptingStream.close();
out.close();

Manejo de excepciones

Al manejar una excepción, puede obtener más información sobre la solicitud HTTP que la ha causado, como el código de estado o tiempo de espera. También puede obtener el ID de solicitud al manejar BmcException mediante el método getOpcRequestId.

En este ejemplo se muestra un bloque try-catch que maneja BmcException e imprime el ID de solicitud.

ObjectStorage client = ...;
try {
    GetBucketResponse response = client.getBucket(
	        GetBucketRequest.builder().namespaceName("myNamespace").bucketName("myBucket").build());
    String requestId = response.getOpcRequestId();
    System.out.println(requestId);
} catch (BmcException e) {
    String requestId = e.getOpcRequestId();
    System.out.println(requestId);
    e.printStackTrace();
}

Las excepciones del SDK para Java son excepciones de tiempo de ejecución (desactivadas), por lo que no se muestran en las firmas de método. Todas las API pueden devolver BmcException.