

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Tutorial Java per Amazon QLDB
<a name="getting-started.java.tutorial"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

In questa implementazione dell'applicazione di esempio del tutorial, utilizzi il driver Amazon QLDB con AWS SDK per Java per creare un registro QLDB e compilarlo con dati di esempio.

Mentre segui questo tutorial, puoi fare riferimento all'API Reference per le operazioni [AWS SDK per Java API](https://docs.aws.amazon.com/sdk-for-java/latest/reference/) di gestione. Per le operazioni sui dati transazionali, puoi fare riferimento al QLDB Driver for Java API [Reference](https://javadoc.io/doc/software.amazon.qldb/amazon-qldb-driver-java/latest/index.html).

**Nota**  
Ove applicabile, alcuni passaggi del tutorial contengono comandi o esempi di codice diversi per ogni versione principale supportata del driver QLDB per Java.

**Topics**
+ [

# Installazione dell'applicazione di esempio Amazon QLDB Java
](sample-app.java.md)
+ [

# Fase 1: Creare un nuovo registro
](getting-started.java.step-1.md)
+ [

# Passaggio 2: verifica la connettività al registro
](getting-started.java.step-2.md)
+ [

# Passaggio 3: Creare tabelle, indici e dati di esempio
](getting-started.java.step-3.md)
+ [

# Passaggio 4: interrogare le tabelle in un libro mastro
](getting-started.java.step-4.md)
+ [

# Fase 5: Modificare i documenti in un libro mastro
](getting-started.java.step-5.md)
+ [

# Fase 6: Visualizzare la cronologia delle revisioni di un documento
](getting-started.java.step-6.md)
+ [

# Passaggio 7: Verificare un documento in un libro mastro
](getting-started.java.step-7.md)
+ [

# Fase 8: Esportazione e convalida dei dati del diario in un libro mastro
](getting-started.java.step-8.md)
+ [

# Passaggio 9 (opzionale): Pulisci le risorse
](getting-started.java.step-9.md)

# Installazione dell'applicazione di esempio Amazon QLDB Java
<a name="sample-app.java"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Questa sezione descrive come installare ed eseguire l'applicazione di esempio Amazon QLDB fornita per step-by-step il tutorial Java. Il caso d'uso di questa applicazione di esempio è un database del Dipartimento dei veicoli a motore (DMV) che tiene traccia delle informazioni storiche complete sulle immatricolazioni dei veicoli.

[L'applicazione di esempio DMV per Java è open source nel repository aws-samples/ -java. GitHub amazon-qldb-dmv-sample](https://github.com/aws-samples/amazon-qldb-dmv-sample-java)

## Prerequisiti
<a name="sample-app.java.prereqs"></a>

Prima di iniziare, assicurati di aver completato il driver QLDB per Java. [Prerequisiti](getting-started.java.md#getting-started.java.prereqs) Questo include gli output seguenti:

1. Iscriviti per. AWS

1. Crea un utente con le autorizzazioni QLDB appropriate. Per completare tutti i passaggi di questo tutorial, è necessario l'accesso amministrativo completo alla risorsa di registro tramite l'API QLDB.

1. Se utilizzi un IDE diverso da quello AWS Cloud9, installa Java e concedi l'accesso programmatico per lo sviluppo.

## Installazione
<a name="sample-app.java.install"></a>

I passaggi seguenti descrivono come scaricare e configurare l'applicazione di esempio con un ambiente di sviluppo locale. In alternativa, è possibile automatizzare la configurazione dell'applicazione di esempio utilizzandola AWS Cloud9 come IDE e un CloudFormation modello per fornire le risorse di sviluppo.

### Ambiente di sviluppo locale
<a name="sample-app.java.local-ide"></a>

Queste istruzioni descrivono come scaricare e installare l'applicazione di esempio Java QLDB utilizzando risorse e ambiente di sviluppo propri.

**Per scaricare ed eseguire l'applicazione di esempio**

1. Immettete il seguente comando da cui clonare l'applicazione di GitHub esempio.

------
#### [ 2.x ]

   ```
   git clone https://github.com/aws-samples/amazon-qldb-dmv-sample-java.git
   ```

------
#### [ 1.x ]

   ```
   git clone -b v1.2.0 https://github.com/aws-samples/amazon-qldb-dmv-sample-java.git
   ```

------

   Questo pacchetto include la configurazione Gradle e il codice completo di. [Tutorial su Java](getting-started.java.tutorial.md)

1. Carica ed esegui l'applicazione fornita.
   + Se stai usando Eclipse:

     1. Avvia Eclipse e, nel menu **Eclipse**, scegli **File**, **Importa**, quindi Progetto **Gradle esistente**.

     1. Nella directory principale del progetto, sfoglia e seleziona la directory dell'applicazione che contiene il file. `build.gradle` Quindi, scegliete **Fine** per utilizzare le impostazioni Gradle predefinite per l'importazione. 

     1. Puoi provare a eseguire il `ListLedgers` programma come esempio. Apri il menu contestuale (fai clic con il pulsante destro del mouse) per il `ListLedgers.java` file e scegli **Esegui come applicazione Java**.
   + Se utilizzi IntelliJ:

     1. **Avviare IntelliJ e nel menu **IntelliJ** scegliere **File**, quindi Apri.**

     1. Nella directory principale del progetto, sfogliate e selezionate la directory dell'applicazione che contiene il `build.gradle` file. Quindi, scegliete **OK**. Mantenete le impostazioni predefinite e scegliete nuovamente **OK**. 

     1. Puoi provare a eseguire il `ListLedgers` programma come esempio. Apri il menu contestuale (fai clic con il pulsante destro del mouse) per il `ListLedgers.java` file e scegli **Esegui 'ListLedgers'**.

1. Procedi con [Fase 1: Creare un nuovo registro](getting-started.java.step-1.md) l'avvio del tutorial e la creazione di un libro mastro.

### AWS Cloud9
<a name="sample-app.java.cfn-ac9"></a>

Queste istruzioni descrivono come automatizzare la configurazione dell'applicazione di esempio per la registrazione di veicoli Amazon QLDB per Java, [AWS Cloud9](https://aws.amazon.com/cloud9)utilizzandola come IDE. In questa guida, utilizzi un [CloudFormation](https://aws.amazon.com/cloudformation)modello per fornire le tue risorse di sviluppo.

Per ulteriori informazioni in merito AWS Cloud9, consulta la [Guida AWS Cloud9 per l'utente](https://docs.aws.amazon.com/cloud9/latest/user-guide/). Per ulteriori informazioni su CloudFormation, consulta la [Guida per l'utente di AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/).

**Topics**
+ [

#### Parte 1: Fornisci le tue risorse
](#sample-app.java.cfn-ac9.step-1)
+ [

#### Parte 2: configura il tuo IDE
](#sample-app.java.cfn-ac9.step-2)
+ [

#### Parte 3: Esecuzione dell'applicazione di esempio QLDB DMV
](#sample-app.java.cfn-ac9.step-3)

#### Parte 1: Fornisci le tue risorse
<a name="sample-app.java.cfn-ac9.step-1"></a>

In questo primo passaggio, devi CloudFormation fornire le risorse necessarie per configurare il tuo ambiente di sviluppo con l'applicazione di esempio Amazon QLDB.

**Per aprire la CloudFormation console e caricare il modello di applicazione di esempio QLDB**

1. [Accedi Console di gestione AWS e apri la CloudFormation console all'indirizzo https://console.aws.amazon.com /cloudformation.](https://console.aws.amazon.com/cloudformation/)

   Passa a una regione che supporta QLDB. Per un elenco completo, consulta gli [endpoint e le quote di Amazon QLDB](https://docs.aws.amazon.com/general/latest/gr/qldb.html) nel. *Riferimenti generali di AWS* La seguente schermata Console di gestione AWS mostra gli Stati Uniti orientali (Virginia settentrionale) come selezionati. Regione AWS  
![\[Console di gestione AWS mostrando Stati Uniti orientali (Virginia settentrionale) come selezionato. Regione AWS\]](http://docs.aws.amazon.com/it_it/qldb/latest/developerguide/images/cfn-ac9/aws-region-us-east-1.png)

1. Sulla CloudFormation console, scegli **Crea stack**, quindi scegli **Con nuove risorse (standard)**.

1. Nella pagina **Crea stack**, sotto **Specificare modello**, scegli l'URL di **Amazon S3**.

1. **Inserisci il seguente URL e scegli Avanti.**

   ```
   https://amazon-qldb-assets.s3.amazonaws.com/templates/QLDB-DMV-SampleApp.yml
   ```

1. Immettete un **nome per lo stack** (ad esempio**qldb-sample-app**) e scegliete **Avanti**.

1. Puoi aggiungere qualsiasi tag appropriato e mantenere le opzioni predefinite. Quindi scegli **Successivo**.

1. Controlla le impostazioni dello stack e scegli **Crea pila**. Il CloudFormation completamento dello script potrebbe richiedere alcuni minuti.

   Questo script effettua il provisioning del tuo AWS Cloud9 ambiente con un'istanza Amazon Elastic Compute Cloud (Amazon EC2) associata che usi per eseguire l'applicazione di esempio QLDB in questo tutorial. Inoltre, clona il repository [amazon-qldb-dmv-sampleaws-samples/](https://github.com/aws-samples/amazon-qldb-dmv-sample-java/) -java dal tuo ambiente di sviluppo. GitHub AWS Cloud9 

#### Parte 2: configura il tuo IDE
<a name="sample-app.java.cfn-ac9.step-2"></a>

In questo passaggio, finisci la configurazione del tuo ambiente di sviluppo cloud. Scarichi ed esegui uno script di shell fornito per configurare l' AWS Cloud9 IDE con le dipendenze dell'applicazione di esempio.

**Per configurare il tuo ambiente AWS Cloud9**

1. Apri la AWS Cloud9 console all'indirizzo [https://console.aws.amazon.com/cloud9/](https://console.aws.amazon.com/cloud9/).

1. **In **I tuoi ambienti**, individua la scheda per l'ambiente denominato **QLDB DMV Sample** Application e scegli Open IDE.** Il caricamento dell'ambiente potrebbe richiedere un minuto all'avvio dell'istanza sottostante. EC2 

   L' AWS Cloud9 ambiente è preconfigurato con le dipendenze di sistema necessarie per eseguire il tutorial. Nel riquadro di navigazione **Ambiente** della console, verifica che sia presente una cartella denominata. `QLDB DMV Sample Application` La seguente schermata della AWS Cloud9 console mostra il riquadro della cartella dell'ambiente QLDB DMV Sample Application.  
![\[AWS Cloud9 console che mostra il riquadro della cartella dell'ambiente QLDB DMV Sample Application.\]](http://docs.aws.amazon.com/it_it/qldb/latest/developerguide/images/cfn-ac9/cloud9-folders.png)

   Se non vedi un pannello di navigazione, attiva la scheda **Ambiente** sul lato sinistro della console. Se non vedi alcuna cartella nel riquadro, abilita **Show Environment Root** usando l'icona delle impostazioni ()![\[Settings icon\]](http://docs.aws.amazon.com/it_it/qldb/latest/developerguide/images/settings.png).

1. Nel riquadro inferiore della console, dovresti vedere una finestra di `bash` terminale aperta. Se non la vedi, scegli **Nuovo terminale** dal menu **Finestra** nella parte superiore della console.

1. Successivamente, scarica ed esegui uno script di installazione per installare OpenJDK 8 e, se applicabile, controlla il ramo appropriato dal repository Git. Nel AWS Cloud9 terminale che hai creato nel passaggio precedente, esegui i due comandi seguenti nell'ordine:

------
#### [ 2.x ]

   ```
   aws s3 cp s3://amazon-qldb-assets/setup-scripts/dmv-setup-v2.sh .
   ```

   ```
   sh dmv-setup-v2.sh
   ```

------
#### [ 1.x ]

   ```
   aws s3 cp s3://amazon-qldb-assets/setup-scripts/dmv-setup.sh .
   ```

   ```
   sh dmv-setup.sh
   ```

------

   Al termine, dovresti vedere il seguente messaggio stampato nel terminale:

   ```
   ** DMV Sample App setup completed , enjoy!! **
   ```

1. Prenditi un momento per sfogliare il codice dell'applicazione di esempio AWS Cloud9, in particolare nel seguente percorso di directory:`src/main/java/software/amazon/qldb/tutorial`.

#### Parte 3: Esecuzione dell'applicazione di esempio QLDB DMV
<a name="sample-app.java.cfn-ac9.step-3"></a>

In questo passaggio, imparerai come eseguire le attività dell'applicazione di esempio Amazon QLDB DMV utilizzando. AWS Cloud9 Per eseguire il codice di esempio, torna al tuo AWS Cloud9 terminale o crea una nuova finestra di terminale come hai fatto nella *Parte 2: Configurazione* dell'IDE.

**Per eseguire l'applicazione di esempio**

1. Esegui il seguente comando nel tuo terminale per passare alla directory principale del progetto:

   ```
   cd ~/environment/amazon-qldb-dmv-sample-java
   ```

   Assicurati di eseguire gli esempi nel seguente percorso di directory.

   ```
   /home/ec2-user/environment/amazon-qldb-dmv-sample-java/
   ```

1. Il comando seguente mostra la sintassi Gradle per eseguire ogni attività.

   ```
   ./gradlew run -Dtutorial=Task
   ```

   Ad esempio, esegui il comando seguente per elencare tutti i registri nella tua regione Account AWS e nella regione corrente.

   ```
   ./gradlew run -Dtutorial=ListLedgers
   ```

1. Procedi con [Fase 1: Creare un nuovo registro](getting-started.java.step-1.md) l'avvio del tutorial e la creazione di un libro mastro.

1. (Facoltativo) Dopo aver completato il tutorial, pulisci CloudFormation le risorse se non ti servono più.

   1. Apri la CloudFormation console in [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/) ed elimina lo stack che hai creato nella *Parte 1:* Fornisci le tue risorse.

   1. Elimina anche lo AWS Cloud9 stack creato dal modello per te. CloudFormation 

# Fase 1: Creare un nuovo registro
<a name="getting-started.java.step-1"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

In questo passaggio, crei un nuovo registro Amazon QLDB denominato. `vehicle-registration`

**Per creare un nuovo libro mastro**

1. Esamina il seguente file (`Constants.java`), che contiene valori costanti utilizzati da tutti gli altri programmi di questo tutorial.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonSystem;
   import com.amazon.ion.system.IonSystemBuilder;
   import com.fasterxml.jackson.databind.SerializationFeature;
   import com.fasterxml.jackson.dataformat.ion.IonObjectMapper;
   import com.fasterxml.jackson.dataformat.ion.ionvalue.IonValueMapper;
   
   /**
    * Constant values used throughout this tutorial.
    */
   public final class Constants {
       public static final int RETRY_LIMIT = 4;
       public static final String LEDGER_NAME = "vehicle-registration";
       public static final String STREAM_NAME = "vehicle-registration-stream";
       public static final String VEHICLE_REGISTRATION_TABLE_NAME = "VehicleRegistration";
       public static final String VEHICLE_TABLE_NAME = "Vehicle";
       public static final String PERSON_TABLE_NAME = "Person";
       public static final String DRIVERS_LICENSE_TABLE_NAME = "DriversLicense";
       public static final String VIN_INDEX_NAME = "VIN";
       public static final String PERSON_GOV_ID_INDEX_NAME = "GovId";
       public static final String VEHICLE_REGISTRATION_LICENSE_PLATE_NUMBER_INDEX_NAME = "LicensePlateNumber";
       public static final String DRIVER_LICENSE_NUMBER_INDEX_NAME = "LicenseNumber";
       public static final String DRIVER_LICENSE_PERSONID_INDEX_NAME = "PersonId";
       public static final String JOURNAL_EXPORT_S3_BUCKET_NAME_PREFIX = "qldb-tutorial-journal-export";
       public static final String USER_TABLES = "information_schema.user_tables";
       public static final String LEDGER_NAME_WITH_TAGS = "tags";
       public static final IonSystem SYSTEM = IonSystemBuilder.standard().build();
       public static final IonObjectMapper MAPPER = new IonValueMapper(SYSTEM);
   
       private Constants() { }
   
       static {
           MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
       }
   }
   ```

------
#### [ 1.x ]

**Importante**  
Per il pacchetto Amazon Ion, devi utilizzare lo spazio dei nomi `com.amazon.ion` nella tua applicazione. AWS SDK per Java Dipende da un altro pacchetto Ion nello spazio dei nomi`software.amazon.ion`, ma si tratta di un pacchetto legacy non compatibile con il driver QLDB.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonSystem;
   import com.amazon.ion.system.IonSystemBuilder;
   import com.fasterxml.jackson.databind.SerializationFeature;
   import com.fasterxml.jackson.dataformat.ion.IonObjectMapper;
   import com.fasterxml.jackson.dataformat.ion.ionvalue.IonValueMapper;
   
   /**
    * Constant values used throughout this tutorial.
    */
   public final class Constants {
       public static final int RETRY_LIMIT = 4;
       public static final String LEDGER_NAME = "vehicle-registration";
       public static final String STREAM_NAME = "vehicle-registration-stream";
       public static final String VEHICLE_REGISTRATION_TABLE_NAME = "VehicleRegistration";
       public static final String VEHICLE_TABLE_NAME = "Vehicle";
       public static final String PERSON_TABLE_NAME = "Person";
       public static final String DRIVERS_LICENSE_TABLE_NAME = "DriversLicense";
       public static final String VIN_INDEX_NAME = "VIN";
       public static final String PERSON_GOV_ID_INDEX_NAME = "GovId";
       public static final String VEHICLE_REGISTRATION_LICENSE_PLATE_NUMBER_INDEX_NAME = "LicensePlateNumber";
       public static final String DRIVER_LICENSE_NUMBER_INDEX_NAME = "LicenseNumber";
       public static final String DRIVER_LICENSE_PERSONID_INDEX_NAME = "PersonId";
       public static final String JOURNAL_EXPORT_S3_BUCKET_NAME_PREFIX = "qldb-tutorial-journal-export";
       public static final String USER_TABLES = "information_schema.user_tables";
       public static final String LEDGER_NAME_WITH_TAGS = "tags";
       public static final IonSystem SYSTEM = IonSystemBuilder.standard().build();
       public static final IonObjectMapper MAPPER = new IonValueMapper(SYSTEM);
   
       private Constants() { }
   
       static {
           MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
       }
   }
   ```

------
**Nota**  
Questa `Constants` classe include un'istanza della classe Jackson open source. `IonValueMapper` Puoi utilizzare questo mappatore per elaborare i dati di [Amazon Ion](ion.md) durante le transazioni di lettura e scrittura.

   Il `CreateLedger.java` file dipende anche dal seguente programma (`DescribeLedger.java`), che descrive lo stato attuale del registro.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.model.DescribeLedgerRequest;
   import com.amazonaws.services.qldb.model.DescribeLedgerResult;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   /**
    * Describe a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class DescribeLedger {
       public static AmazonQLDB client = CreateLedger.getClient();
       public static final Logger log = LoggerFactory.getLogger(DescribeLedger.class);
   
       private DescribeLedger() { }
   
       public static void main(final String... args) {
           try {
   
               describe(Constants.LEDGER_NAME);
   
           } catch (Exception e) {
               log.error("Unable to describe a ledger!", e);
           }
       }
   
       /**
        * Describe a ledger.
        *
        * @param name
        *              Name of the ledger to describe.
        * @return {@link DescribeLedgerResult} from QLDB.
        */
       public static DescribeLedgerResult describe(final String name) {
           log.info("Let's describe ledger with name: {}...", name);
           DescribeLedgerRequest request = new DescribeLedgerRequest().withName(name);
           DescribeLedgerResult result = client.describeLedger(request);
           log.info("Success. Ledger description: {}", result);
           return result;
       }
   }
   ```

1. Compila ed esegui il `CreateLedger.java` programma per creare un registro denominato. `vehicle-registration`

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.client.builder.AwsClientBuilder;
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.AmazonQLDBClientBuilder;
   import com.amazonaws.services.qldb.model.CreateLedgerRequest;
   import com.amazonaws.services.qldb.model.CreateLedgerResult;
   import com.amazonaws.services.qldb.model.DescribeLedgerResult;
   import com.amazonaws.services.qldb.model.LedgerState;
   import com.amazonaws.services.qldb.model.PermissionsMode;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   /**
    * Create a ledger and wait for it to be active.
    * <p>
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class CreateLedger {
       public static final Logger log = LoggerFactory.getLogger(CreateLedger.class);
       public static final Long LEDGER_CREATION_POLL_PERIOD_MS = 10_000L;
       public static String endpoint = null;
       public static String region = null;
       public static AmazonQLDB client = getClient();
   
       private CreateLedger() {
       }
   
       /**
        * Build a low-level QLDB client.
        *
        * @return {@link AmazonQLDB} control plane client.
        */
       public static AmazonQLDB getClient() {
           AmazonQLDBClientBuilder builder = AmazonQLDBClientBuilder.standard();
           if (null != endpoint && null != region) {
               builder.setEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region));
           }
           return builder.build();
       }
   
       public static void main(final String... args) throws Exception {
           try {
               client = getClient();
   
               create(Constants.LEDGER_NAME);
   
               waitForActive(Constants.LEDGER_NAME);
   
           } catch (Exception e) {
               log.error("Unable to create the ledger!", e);
               throw e;
           }
       }
   
       /**
        * Create a new ledger with the specified ledger name.
        *
        * @param ledgerName Name of the ledger to be created.
        * @return {@link CreateLedgerResult} from QLDB.
        */
       public static CreateLedgerResult create(final String ledgerName) {
           log.info("Let's create the ledger with name: {}...", ledgerName);
           CreateLedgerRequest request = new CreateLedgerRequest()
                   .withName(ledgerName)
                   .withPermissionsMode(PermissionsMode.ALLOW_ALL);
           CreateLedgerResult result = client.createLedger(request);
           log.info("Success. Ledger state: {}.", result.getState());
           return result;
       }
   
       /**
        * Wait for a newly created ledger to become active.
        *
        * @param ledgerName Name of the ledger to wait on.
        * @return {@link DescribeLedgerResult} from QLDB.
        * @throws InterruptedException if thread is being interrupted.
        */
       public static DescribeLedgerResult waitForActive(final String ledgerName) throws InterruptedException {
           log.info("Waiting for ledger to become active...");
           while (true) {
               DescribeLedgerResult result = DescribeLedger.describe(ledgerName);
               if (result.getState().equals(LedgerState.ACTIVE.name())) {
                   log.info("Success. Ledger is active and ready to use.");
                   return result;
               }
               log.info("The ledger is still creating. Please wait...");
               Thread.sleep(LEDGER_CREATION_POLL_PERIOD_MS);
           }
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.AmazonQLDBClientBuilder;
   import com.amazonaws.services.qldb.model.CreateLedgerRequest;
   import com.amazonaws.services.qldb.model.CreateLedgerResult;
   import com.amazonaws.services.qldb.model.DescribeLedgerResult;
   import com.amazonaws.services.qldb.model.LedgerState;
   import com.amazonaws.services.qldb.model.PermissionsMode;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   /**
    * Create a ledger and wait for it to be active.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class CreateLedger {
       public static final Logger log = LoggerFactory.getLogger(CreateLedger.class);
       public static final Long LEDGER_CREATION_POLL_PERIOD_MS = 10_000L;
       public static AmazonQLDB client = getClient();
   
       private CreateLedger() { }
   
       /**
        * Build a low-level QLDB client.
        *
        * @return {@link AmazonQLDB} control plane client.
        */
       public static AmazonQLDB getClient() {
           return AmazonQLDBClientBuilder.standard().build();
       }
   
       public static void main(final String... args) throws Exception {
           try {
   
               create(Constants.LEDGER_NAME);
   
               waitForActive(Constants.LEDGER_NAME);
   
           } catch (Exception e) {
               log.error("Unable to create the ledger!", e);
               throw e;
           }
       }
   
       /**
        * Create a new ledger with the specified ledger name.
        *
        * @param ledgerName
        *              Name of the ledger to be created.
        * @return {@link CreateLedgerResult} from QLDB.
        */
       public static CreateLedgerResult create(final String ledgerName) {
           log.info("Let's create the ledger with name: {}...", ledgerName);
           CreateLedgerRequest request = new CreateLedgerRequest()
                   .withName(ledgerName)
                   .withPermissionsMode(PermissionsMode.ALLOW_ALL);
           CreateLedgerResult result = client.createLedger(request);
           log.info("Success. Ledger state: {}.", result.getState());
           return result;
       }
   
       /**
        * Wait for a newly created ledger to become active.
        *
        * @param ledgerName
        *              Name of the ledger to wait on.
        * @return {@link DescribeLedgerResult} from QLDB.
        * @throws InterruptedException if thread is being interrupted.
        */
       public static DescribeLedgerResult waitForActive(final String ledgerName) throws InterruptedException {
           log.info("Waiting for ledger to become active...");
           while (true) {
               DescribeLedgerResult result = DescribeLedger.describe(ledgerName);
               if (result.getState().equals(LedgerState.ACTIVE.name())) {
                   log.info("Success. Ledger is active and ready to use.");
                   return result;
               }
               log.info("The ledger is still creating. Please wait...");
               Thread.sleep(LEDGER_CREATION_POLL_PERIOD_MS);
           }
       }
   }
   ```

------
**Nota**  
Nella `createLedger` chiamata, è necessario specificare un nome di registro e una modalità di autorizzazione. Ti consigliamo di utilizzare la modalità `STANDARD` autorizzazioni per massimizzare la sicurezza dei dati del registro.
Quando si crea un registro, la *protezione da eliminazione* è abilitata per impostazione predefinita. Questa è una funzionalità di QLDB che impedisce l'eliminazione dei registri da parte di qualsiasi utente. È possibile disabilitare la protezione da eliminazione durante la creazione del registro utilizzando l'API QLDB o il (). AWS Command Line Interface AWS CLI
Facoltativamente, puoi anche specificare i tag da allegare al tuo libro mastro.

Per verificare la connessione al nuovo registro, procedi a. [Passaggio 2: verifica la connettività al registro](getting-started.java.step-2.md)

# Passaggio 2: verifica la connettività al registro
<a name="getting-started.java.step-2"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

In questo passaggio, verifichi di poterti connettere al `vehicle-registration` registro in Amazon QLDB utilizzando l'endpoint API dei dati transazionali.

**Per testare la connettività al registro**

1. Esamina il seguente programma (`ConnectToLedger.java`), che crea una connessione della sessione di dati al `vehicle-registration` registro.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import java.net.URI;
   import java.net.URISyntaxException;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
   import software.amazon.awssdk.services.qldbsession.QldbSessionClient;
   import software.amazon.awssdk.services.qldbsession.QldbSessionClientBuilder;
   import software.amazon.qldb.QldbDriver;
   import software.amazon.qldb.RetryPolicy;
   
   /**
    * Connect to a session for a given ledger using default settings.
    * <p>
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class ConnectToLedger {
       public static final Logger log = LoggerFactory.getLogger(ConnectToLedger.class);
       public static AwsCredentialsProvider credentialsProvider;
       public static String endpoint = null;
       public static String ledgerName = Constants.LEDGER_NAME;
       public static String region = null;
       public static QldbDriver driver;
   
       private ConnectToLedger() {
       }
   
       /**
        * Create a pooled driver for creating sessions.
        *
        * @param retryAttempts How many times the transaction will be retried in
        * case of a retryable issue happens like Optimistic Concurrency Control exception,
        * server side failures or network issues.
        * @return The pooled driver for creating sessions.
        */
       public static QldbDriver createQldbDriver(int retryAttempts) {
           QldbSessionClientBuilder builder = getAmazonQldbSessionClientBuilder();
           return QldbDriver.builder()
                                .ledger(ledgerName)
                                .transactionRetryPolicy(RetryPolicy
                                      .builder()
                                      .maxRetries(retryAttempts)
                                      .build())
                                .sessionClientBuilder(builder)
                                .build();
       }
   
       /**
        * Create a pooled driver for creating sessions.
        *
        * @return The pooled driver for creating sessions.
        */
       public static QldbDriver createQldbDriver() {
           QldbSessionClientBuilder builder = getAmazonQldbSessionClientBuilder();
           return QldbDriver.builder()
               .ledger(ledgerName)
               .transactionRetryPolicy(RetryPolicy.builder()
                                                  .maxRetries(Constants.RETRY_LIMIT).build())
               .sessionClientBuilder(builder)
               .build();
       }
   
       /**
        * Creates a QldbSession builder that is passed to the QldbDriver to connect to the Ledger.
        *
        * @return An instance of the AmazonQLDBSessionClientBuilder
        */
       public static QldbSessionClientBuilder getAmazonQldbSessionClientBuilder() {
           QldbSessionClientBuilder builder = QldbSessionClient.builder();
           if (null != endpoint && null != region) {
               try {
                   builder.endpointOverride(new URI(endpoint));
               } catch (URISyntaxException e) {
                   throw new IllegalArgumentException(e);
               }
           }
           if (null != credentialsProvider) {
               builder.credentialsProvider(credentialsProvider);
           }
           return builder;
       }
   
       /**
        * Create a pooled driver for creating sessions.
        *
        * @return The pooled driver for creating sessions.
        */
       public static QldbDriver getDriver() {
           if (driver == null) {
               driver = createQldbDriver();
           }
           return driver;
       }
   
   
       public static void main(final String... args) {
           Iterable<String> tables = ConnectToLedger.getDriver().getTableNames();
           log.info("Existing tables in the ledger:");
           for (String table : tables) {
               log.info("- {} ", table);
           }
       }
   }
   ```

**Nota**  
Per eseguire operazioni sui dati sul registro, è necessario creare un'istanza della `QldbDriver` classe per connettersi a un registro specifico. Si tratta di un oggetto client diverso dal `AmazonQLDB` client utilizzato nel passaggio precedente per creare il registro. Quel client precedente viene utilizzato solo per eseguire le operazioni dell'API di gestione elencate in. [Riferimento all'API Amazon QLDB](api-reference.md)
Innanzitutto, crea un `QldbDriver` oggetto. È necessario specificare un nome contabile quando si crea questo driver.  
Quindi, è possibile utilizzare il `execute` metodo di questo driver per eseguire istruzioni PartiQL.
Facoltativamente, è possibile specificare un numero massimo di tentativi di nuovo tentativo per le eccezioni delle transazioni. Il `execute` metodo riprova automaticamente i conflitti OCC (Optimistic Concurrency Control) e altre eccezioni transitorie comuni entro questo limite configurabile. Il valore predefinito è `4`.  
Se la transazione continua a fallire dopo il raggiungimento del limite, il driver genera l'eccezione. Per ulteriori informazioni, consulta [Comprendere la politica dei nuovi tentativi con il driver in Amazon QLDB](driver-retry-policy.md).

------
#### [ 1.x ]

   ```
   /*
    * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.auth.AWSCredentialsProvider;
   import com.amazonaws.client.builder.AwsClientBuilder;
   import com.amazonaws.services.qldbsession.AmazonQLDBSessionClientBuilder;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.PooledQldbDriver;
   import software.amazon.qldb.QldbDriver;
   import software.amazon.qldb.QldbSession;
   import software.amazon.qldb.exceptions.QldbClientException;
   
   /**
    * Connect to a session for a given ledger using default settings.
    * <p>
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class ConnectToLedger {
       public static final Logger log = LoggerFactory.getLogger(ConnectToLedger.class);
       public static AWSCredentialsProvider credentialsProvider;
       public static String endpoint = null;
       public static String ledgerName = Constants.LEDGER_NAME;
       public static String region = null;
       private static PooledQldbDriver driver;
   
       private ConnectToLedger() {
       }
   
       /**
        * Create a pooled driver for creating sessions.
        *
        * @return The pooled driver for creating sessions.
        */
       public static PooledQldbDriver createQldbDriver() {
           AmazonQLDBSessionClientBuilder builder = AmazonQLDBSessionClientBuilder.standard();
           if (null != endpoint && null != region) {
               builder.setEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint, region));
           }
           if (null != credentialsProvider) {
               builder.setCredentials(credentialsProvider);
           }
           return PooledQldbDriver.builder()
                   .withLedger(ledgerName)
                   .withRetryLimit(Constants.RETRY_LIMIT)
                   .withSessionClientBuilder(builder)
                   .build();
       }
   
       /**
        * Create a pooled driver for creating sessions.
        *
        * @return The pooled driver for creating sessions.
        */
       public static PooledQldbDriver getDriver() {
           if (driver == null) {
               driver = createQldbDriver();
           }
           return driver;
       }
   
       /**
        * Connect to a ledger through a {@link QldbDriver}.
        *
        * @return {@link QldbSession}.
        */
       public static QldbSession createQldbSession() {
           return getDriver().getSession();
       }
   
       public static void main(final String... args) {
           try (QldbSession qldbSession = createQldbSession()) {
               log.info("Listing table names ");
               for (String tableName : qldbSession.getTableNames()) {
                   log.info(tableName);
               }
           } catch (QldbClientException e) {
               log.error("Unable to create session.", e);
           }
       }
   }
   ```

**Nota**  
Per eseguire operazioni sui dati sul registro, è necessario creare un'istanza della `QldbDriver` classe `PooledQldbDriver` or per connettersi a un registro specifico. Si tratta di un oggetto client diverso dal `AmazonQLDB` client utilizzato nel passaggio precedente per creare il registro. Quel client precedente viene utilizzato solo per eseguire le operazioni dell'API di gestione elencate in. [Riferimento all'API Amazon QLDB](api-reference.md)  
Si consiglia di utilizzare, `PooledQldbDriver` a meno che non sia necessario implementare un pool di sessioni personalizzato con`QldbDriver`. La dimensione predefinita del pool `PooledQldbDriver` è il [numero massimo di connessioni HTTP aperte](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html#getMaxConnections--) consentite dal client di sessione.
Innanzitutto, crea un `PooledQldbDriver` oggetto. È necessario specificare un nome contabile quando si crea questo driver.  
Quindi, è possibile utilizzare il `execute` metodo di questo driver per eseguire istruzioni PartiQL. In alternativa, è possibile creare manualmente una sessione da questo oggetto driver in pool e utilizzare il metodo della `execute` sessione. Una sessione rappresenta una singola connessione con il registro.
Facoltativamente, è possibile specificare un numero massimo di tentativi per le eccezioni delle transazioni. Il `execute` metodo riprova automaticamente i conflitti OCC (Optimistic Concurrency Control) e altre eccezioni transitorie comuni entro questo limite configurabile. Il valore predefinito è `4`.  
Se la transazione continua a fallire dopo il raggiungimento del limite, il driver genera l'eccezione. Per ulteriori informazioni, consulta [Comprendere la politica dei nuovi tentativi con il driver in Amazon QLDB](driver-retry-policy.md).

------

1. Compila ed esegui il `ConnectToLedger.java` programma per testare la connettività della sessione di dati al `vehicle-registration` registro.

**Sovrascrivere il Regione AWS**

L'applicazione di esempio si connette a QLDB come Regione AWS impostazione predefinita, che puoi impostare come descritto nel passaggio dei prerequisiti. [Impostazione delle AWS credenziali e della regione predefinite](getting-started.java.md#getting-started.java.credentials) È inoltre possibile modificare la regione modificando le proprietà del generatore del client di sessione QLDB.

------
#### [ 2.x ]

Il seguente esempio di codice crea un'istanza di un nuovo oggetto. `QldbSessionClientBuilder`

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.qldbsession.QldbSessionClientBuilder;

// This client builder will default to US East (Ohio)
QldbSessionClientBuilder builder = QldbSessionClient.builder()
    .region(Region.US_EAST_2);
```

Puoi utilizzare il `region` metodo per eseguire il codice su QLDB in qualsiasi regione in cui è disponibile. Per un elenco completo, consulta gli [endpoint e le quote di Amazon QLDB](https://docs.aws.amazon.com/general/latest/gr/qldb.html) nel. *Riferimenti generali di AWS*

------
#### [ 1.x ]

Il seguente esempio di codice crea un'istanza di un nuovo oggetto. `AmazonQLDBSessionClientBuilder`

```
import com.amazonaws.regions.Regions;
import com.amazonaws.services.qldbsession.AmazonQLDBSessionClientBuilder;

// This client builder will default to US East (Ohio)
AmazonQLDBSessionClientBuilder builder = AmazonQLDBSessionClientBuilder.standard()
    .withRegion(Regions.US_EAST_2);
```

Puoi utilizzare il `withRegion` metodo per eseguire il codice su QLDB in qualsiasi regione in cui è disponibile. Per un elenco completo, consulta gli [endpoint e le quote di Amazon QLDB](https://docs.aws.amazon.com/general/latest/gr/qldb.html) nel. *Riferimenti generali di AWS*

------

Per creare tabelle nel `vehicle-registration` registro, procedi a. [Passaggio 3: Creare tabelle, indici e dati di esempio](getting-started.java.step-3.md)

# Passaggio 3: Creare tabelle, indici e dati di esempio
<a name="getting-started.java.step-3"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Quando il tuo registro Amazon QLDB è attivo e accetta connessioni, puoi iniziare a creare tabelle per i dati sui veicoli, i loro proprietari e le loro informazioni di immatricolazione. Dopo aver creato le tabelle e gli indici, puoi caricarli con i dati.

In questo passaggio, crei quattro tabelle nel `vehicle-registration` registro:
+ `VehicleRegistration`
+ `Vehicle`
+ `Person`
+ `DriversLicense`

Vengono inoltre creati i seguenti indici.


****  

| Nome tabella | Campo | 
| --- | --- | 
| VehicleRegistration | VIN | 
| VehicleRegistration | LicensePlateNumber | 
| Vehicle | VIN | 
| Person | GovId | 
| DriversLicense | LicenseNumber | 
| DriversLicense | PersonId | 

Quando si inseriscono dati di esempio, si inseriscono innanzitutto i documenti nella tabella. `Person` Quindi, si utilizzano i dati assegnati `id` dal sistema a ciascun `Person` documento per compilare i campi corrispondenti nei documenti e nei documenti appropriati. `VehicleRegistration` `DriversLicense`

**Suggerimento**  
Come procedura ottimale, utilizzate il sistema assegnato a un documento come chiave esterna`id`. Sebbene sia possibile definire campi destinati a essere identificatori univoci (ad esempio, il VIN di un veicolo), il vero identificatore univoco di un documento è il suo. `id` Questo campo è incluso nei metadati del documento, a cui è possibile eseguire una query nella visualizzazione confermata (*la vista* di una tabella definita dal sistema).  
Per ulteriori informazioni sulle viste in QLDB, vedere. [Concetti principali](ledger-structure.md) Per ulteriori informazioni sui metadati, consulta. [Interrogazione dei metadati dei documenti](working.metadata.md)

**Per configurare i dati di esempio**

1. Esamina i seguenti `.java` file. Queste classi di modelli rappresentano i documenti archiviati nelle `vehicle-registration` tabelle. Sono serializzabili da e verso il formato Amazon Ion.
**Nota**  
[Documenti Amazon QLDB](ql-reference.docs.md)sono archiviati in formato Ion, che è un superset di JSON. Quindi, puoi usare la libreria FasterXML Jackson per modellare i dati in JSON.

   1. `DriversLicense.java`

      ```
      /*
       * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
      import com.fasterxml.jackson.databind.annotation.JsonSerialize;
      import software.amazon.qldb.tutorial.model.streams.RevisionData;
      
      import java.time.LocalDate;
      
      /**
       * Represents a driver's license, serializable to (and from) Ion.
       */
      public final class DriversLicense implements RevisionData {
          private final String personId;
          private final String licenseNumber;
          private final String licenseType;
      
          @JsonSerialize(using = IonLocalDateSerializer.class)
          @JsonDeserialize(using = IonLocalDateDeserializer.class)
          private final LocalDate validFromDate;
      
          @JsonSerialize(using = IonLocalDateSerializer.class)
          @JsonDeserialize(using = IonLocalDateDeserializer.class)
          private final LocalDate validToDate;
      
          @JsonCreator
          public DriversLicense(@JsonProperty("PersonId") final String personId,
                                @JsonProperty("LicenseNumber") final String licenseNumber,
                                @JsonProperty("LicenseType") final String licenseType,
                                @JsonProperty("ValidFromDate") final LocalDate validFromDate,
                                @JsonProperty("ValidToDate") final LocalDate validToDate) {
              this.personId = personId;
              this.licenseNumber = licenseNumber;
              this.licenseType = licenseType;
              this.validFromDate = validFromDate;
              this.validToDate = validToDate;
          }
      
          @JsonProperty("PersonId")
          public String getPersonId() {
              return personId;
          }
      
          @JsonProperty("LicenseNumber")
          public String getLicenseNumber() {
              return licenseNumber;
          }
      
          @JsonProperty("LicenseType")
          public String getLicenseType() {
              return licenseType;
          }
      
          @JsonProperty("ValidFromDate")
          public LocalDate getValidFromDate() {
              return  validFromDate;
          }
      
          @JsonProperty("ValidToDate")
          public LocalDate getValidToDate() {
              return  validToDate;
          }
      
          @Override
          public String toString() {
              return "DriversLicense{" +
                      "personId='" + personId + '\'' +
                      ", licenseNumber='" + licenseNumber + '\'' +
                      ", licenseType='" + licenseType + '\'' +
                      ", validFromDate=" + validFromDate +
                      ", validToDate=" + validToDate +
                      '}';
          }
      }
      ```

   1. `Person.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import java.time.LocalDate;
      
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
      import com.fasterxml.jackson.databind.annotation.JsonSerialize;
      
      import software.amazon.qldb.TransactionExecutor;
      import software.amazon.qldb.tutorial.Constants;
      import software.amazon.qldb.tutorial.model.streams.RevisionData;
      
      /**
       * Represents a person, serializable to (and from) Ion.
       */ 
      public final class Person implements RevisionData {
          private final String firstName;
          private final String lastName;
      
          @JsonSerialize(using = IonLocalDateSerializer.class)
          @JsonDeserialize(using = IonLocalDateDeserializer.class)
          private final LocalDate dob;
          private final String govId;
          private final String govIdType;
          private final String address;
      
          @JsonCreator
          public Person(@JsonProperty("FirstName") final String firstName,
                        @JsonProperty("LastName") final String lastName,
                        @JsonProperty("DOB") final LocalDate dob,
                        @JsonProperty("GovId") final String govId,
                        @JsonProperty("GovIdType") final String govIdType,
                        @JsonProperty("Address") final String address) {
              this.firstName = firstName;
              this.lastName = lastName;
              this.dob = dob;
              this.govId = govId;
              this.govIdType = govIdType;
              this.address = address;
          }
      
          @JsonProperty("Address")
          public String getAddress() {
              return address;
          }
      
          @JsonProperty("DOB")
          public LocalDate getDob() {
              return dob;
          }
      
          @JsonProperty("FirstName")
          public String getFirstName() {
              return firstName;
          }
      
          @JsonProperty("LastName")
          public String getLastName() {
              return lastName;
          }
      
          @JsonProperty("GovId")
          public String getGovId() {
              return govId;
          }
      
          @JsonProperty("GovIdType")
          public String getGovIdType() {
              return govIdType;
          }
      
          /**
           * This returns the unique document ID given a specific government ID.
           *
           * @param txn
           *              A transaction executor object.
           * @param govId
           *              The government ID of a driver.
           * @return the unique document ID.
           */
          public static String getDocumentIdByGovId(final TransactionExecutor txn, final String govId) {
              return SampleData.getDocumentId(txn, Constants.PERSON_TABLE_NAME, "GovId", govId);
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "firstName='" + firstName + '\'' +
                      ", lastName='" + lastName + '\'' +
                      ", dob=" + dob +
                      ", govId='" + govId + '\'' +
                      ", govIdType='" + govIdType + '\'' +
                      ", address='" + address + '\'' +
                      '}';
          }
      }
      ```

   1. `VehicleRegistration.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
      import com.fasterxml.jackson.databind.annotation.JsonSerialize;
      import software.amazon.qldb.TransactionExecutor;
      import software.amazon.qldb.tutorial.Constants;
      import software.amazon.qldb.tutorial.model.streams.RevisionData;
      
      import java.math.BigDecimal;
      import java.time.LocalDate;
      
      /**
       * Represents a vehicle registration, serializable to (and from) Ion.
       */ 
      public final class VehicleRegistration implements RevisionData {
      
          private final String vin;
          private final String licensePlateNumber;
          private final String state;
          private final String city;
          private final BigDecimal pendingPenaltyTicketAmount;
          private final LocalDate validFromDate;
          private final LocalDate validToDate;
          private final Owners owners;
      
          @JsonCreator
          public VehicleRegistration(@JsonProperty("VIN") final String vin,
                                     @JsonProperty("LicensePlateNumber") final String licensePlateNumber,
                                     @JsonProperty("State") final String state,
                                     @JsonProperty("City") final String city,
                                     @JsonProperty("PendingPenaltyTicketAmount") final BigDecimal pendingPenaltyTicketAmount,
                                     @JsonProperty("ValidFromDate") final LocalDate validFromDate,
                                     @JsonProperty("ValidToDate") final LocalDate validToDate,
                                     @JsonProperty("Owners") final Owners owners) {
              this.vin = vin;
              this.licensePlateNumber = licensePlateNumber;
              this.state = state;
              this.city = city;
              this.pendingPenaltyTicketAmount = pendingPenaltyTicketAmount;
              this.validFromDate = validFromDate;
              this.validToDate = validToDate;
              this.owners = owners;
          }
      
          @JsonProperty("City")
          public String getCity() {
              return city;
          }
      
          @JsonProperty("LicensePlateNumber")
          public String getLicensePlateNumber() {
              return licensePlateNumber;
          }
      
          @JsonProperty("Owners")
          public Owners getOwners() {
              return owners;
          }
      
          @JsonProperty("PendingPenaltyTicketAmount")
          public BigDecimal getPendingPenaltyTicketAmount() {
              return pendingPenaltyTicketAmount;
          }
      
          @JsonProperty("State")
          public String getState() {
              return state;
          }
      
          @JsonProperty("ValidFromDate")
          @JsonSerialize(using = IonLocalDateSerializer.class)
          @JsonDeserialize(using = IonLocalDateDeserializer.class)
          public LocalDate getValidFromDate() {
              return validFromDate;
          }
      
          @JsonProperty("ValidToDate")
          @JsonSerialize(using = IonLocalDateSerializer.class)
          @JsonDeserialize(using = IonLocalDateDeserializer.class)
          public LocalDate getValidToDate() {
              return validToDate;
          }
      
          @JsonProperty("VIN")
          public String getVin() {
              return vin;
          }
      
          /**
           * Returns the unique document ID of a vehicle given a specific VIN.
           *
           * @param txn
           *              A transaction executor object.
           * @param vin
           *              The VIN of a vehicle.
           * @return the unique document ID of the specified vehicle.
           */
          public static String getDocumentIdByVin(final TransactionExecutor txn, final String vin) {
              return SampleData.getDocumentId(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME, "VIN", vin);
          }
      
          @Override
          public String toString() {
              return "VehicleRegistration{" +
                      "vin='" + vin + '\'' +
                      ", licensePlateNumber='" + licensePlateNumber + '\'' +
                      ", state='" + state + '\'' +
                      ", city='" + city + '\'' +
                      ", pendingPenaltyTicketAmount=" + pendingPenaltyTicketAmount +
                      ", validFromDate=" + validFromDate +
                      ", validToDate=" + validToDate +
                      ", owners=" + owners +
                      '}';
          }
      }
      ```

   1. `Vehicle.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import software.amazon.qldb.tutorial.model.streams.RevisionData;
      
      /**
       * Represents a vehicle, serializable to (and from) Ion.
       */
      public final class Vehicle implements RevisionData {
          private final String vin;
          private final String type;
          private final int year;
          private final String make;
          private final String model;
          private final String color;
      
          @JsonCreator
          public Vehicle(@JsonProperty("VIN") final String vin,
                         @JsonProperty("Type") final String type,
                         @JsonProperty("Year") final int year,
                         @JsonProperty("Make") final String make,
                         @JsonProperty("Model") final String model,
                         @JsonProperty("Color") final String color) {
              this.vin = vin;
              this.type = type;
              this.year = year;
              this.make = make;
              this.model = model;
              this.color = color;
          }
      
          @JsonProperty("Color")
          public String getColor() {
              return color;
          }
      
          @JsonProperty("Make")
          public String getMake() {
              return make;
          }
      
          @JsonProperty("Model")
          public String getModel() {
              return model;
          }
      
          @JsonProperty("Type")
          public String getType() {
              return type;
          }
      
          @JsonProperty("VIN")
          public String getVin() {
              return vin;
          }
      
          @JsonProperty("Year")
          public int getYear() {
              return year;
          }
      
          @Override
          public String toString() {
              return "Vehicle{" +
                      "vin='" + vin + '\'' +
                      ", type='" + type + '\'' +
                      ", year=" + year +
                      ", make='" + make + '\'' +
                      ", model='" + model + '\'' +
                      ", color='" + color + '\'' +
                      '}';
          }
      }
      ```

   1. `Owner.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.fasterxml.jackson.annotation.JsonProperty;
      
      /**
       * Represents a vehicle owner, serializable to (and from) Ion.
       */ 
      public final class Owner {
          private final String personId;
      
          public Owner(@JsonProperty("PersonId") final String personId) {
              this.personId = personId;
          }
      
          @JsonProperty("PersonId")
          public String getPersonId() {
              return personId;
          }
      
          @Override
          public String toString() {
              return "Owner{" +
                      "personId='" + personId + '\'' +
                      '}';
          }
      }
      ```

   1. `Owners.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.fasterxml.jackson.annotation.JsonProperty;
      
      import java.util.List;
      
      /**
       * Represents a set of owners for a given vehicle, serializable to (and from) Ion.
       */ 
      public final class Owners {
          private final Owner primaryOwner;
          private final List<Owner> secondaryOwners;
      
          public Owners(@JsonProperty("PrimaryOwner") final Owner primaryOwner,
                        @JsonProperty("SecondaryOwners") final List<Owner> secondaryOwners) {
              this.primaryOwner = primaryOwner;
              this.secondaryOwners = secondaryOwners;
          }
      
          @JsonProperty("PrimaryOwner")
          public Owner getPrimaryOwner() {
              return primaryOwner;
          }
      
          @JsonProperty("SecondaryOwners")
          public List<Owner> getSecondaryOwners() {
              return secondaryOwners;
          }
      
          @Override
          public String toString() {
              return "Owners{" +
                      "primaryOwner=" + primaryOwner +
                      ", secondaryOwners=" + secondaryOwners +
                      '}';
          }
      }
      ```

   1. `DmlResultDocument.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      
      /**
       * Contains information about an individual document inserted or modified
       * as a result of DML.
       */
      public class DmlResultDocument {
      
          private String documentId;
      
          @JsonCreator
          public DmlResultDocument(@JsonProperty("documentId") final String documentId) {
              this.documentId = documentId;
          }
      
          public String getDocumentId() {
              return documentId;
          }
      
          @Override
          public String toString() {
              return "DmlResultDocument{"
                  + "documentId='" + documentId + '\''
                  + '}';
          }
      }
      ```

   1. `RevisionData.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model.streams;
      
      /**
       * Allows modeling the content of all revisions as a generic revision data. Used
       * in the {@link Revision} and extended by domain models in {@link
       * software.amazon.qldb.tutorial.model} to make it easier to write the {@link
       * Revision.RevisionDataDeserializer} that must deserialize the {@link
       * Revision#data} from different domain models.
       */
      public interface RevisionData { }
      ```

   1. `RevisionMetadata.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import com.amazon.ion.IonInt;
      import com.amazon.ion.IonString;
      import com.amazon.ion.IonStruct;
      import com.amazon.ion.IonTimestamp;
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import com.fasterxml.jackson.databind.annotation.JsonSerialize;
      import com.fasterxml.jackson.dataformat.ion.IonTimestampSerializers;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import java.util.Date;
      import java.util.Objects;
      
      /**
       * Represents the metadata field of a QLDB Document
       */
      public class RevisionMetadata {
          private static final Logger log = LoggerFactory.getLogger(RevisionMetadata.class);
          private final String id;
          private final long version;
          @JsonSerialize(using = IonTimestampSerializers.IonTimestampJavaDateSerializer.class)
          private final Date txTime;
          private final String txId;
      
          @JsonCreator
          public RevisionMetadata(@JsonProperty("id") final String id,
                                  @JsonProperty("version") final long version,
                                  @JsonProperty("txTime") final Date txTime,
                                  @JsonProperty("txId") final String txId) {
              this.id = id;
              this.version = version;
              this.txTime = txTime;
              this.txId = txId;
          }
      
          /**
           * Gets the unique ID of a QLDB document.
           *
           * @return the document ID.
           */
          public String getId() {
              return id;
          }
      
          /**
           * Gets the version number of the document in the document's modification history.
           * @return the version number.
           */
          public long getVersion() {
              return version;
          }
      
          /**
           * Gets the time during which the document was modified.
           *
           * @return the transaction time.
           */
          public Date getTxTime() {
              return txTime;
          }
      
          /**
           * Gets the transaction ID associated with this document.
           *
           * @return the transaction ID.
           */
          public String getTxId() {
              return txId;
          }
      
          public static RevisionMetadata fromIon(final IonStruct ionStruct) {
              if (ionStruct == null) {
                  throw new IllegalArgumentException("Metadata cannot be null");
              }
              try {
                  IonString id = (IonString) ionStruct.get("id");
                  IonInt version = (IonInt) ionStruct.get("version");
                  IonTimestamp txTime = (IonTimestamp) ionStruct.get("txTime");
                  IonString txId = (IonString) ionStruct.get("txId");
                  if (id == null || version == null || txTime == null || txId == null) {
                      throw new IllegalArgumentException("Document is missing required fields");
                  }
                  return new RevisionMetadata(id.stringValue(), version.longValue(), new Date(txTime.getMillis()), txId.stringValue());
              } catch (ClassCastException e) {
                  log.error("Failed to parse ion document");
                  throw new IllegalArgumentException("Document members are not of the correct type", e);
              }
          }
      
          /**
           * Converts a {@link RevisionMetadata} object to a string.
           *
           * @return the string representation of the {@link QldbRevision} object.
           */
          @Override
          public String toString() {
              return "Metadata{"
                      + "id='" + id + '\''
                      + ", version=" + version
                      + ", txTime=" + txTime
                      + ", txId='" + txId
                      + '\''
                      + '}';
          }
      
          /**
           * Check whether two {@link RevisionMetadata} objects are equivalent.
           *
           * @return {@code true} if the two objects are equal, {@code false} otherwise.
           */
          @Override
          public boolean equals(Object o) {
              if (this == o) { return true; }
              if (o == null || getClass() != o.getClass()) { return false; }
              RevisionMetadata metadata = (RevisionMetadata) o;
              return version == metadata.version
                      && id.equals(metadata.id)
                      && txTime.equals(metadata.txTime)
                      && txId.equals(metadata.txId);
          }
      
          /**
           * Generate a hash code for the {@link RevisionMetadata} object.
           *
           * @return the hash code.
           */
          @Override
          public int hashCode() {
              // CHECKSTYLE:OFF - Disabling as we are generating a hashCode of multiple properties.
              return Objects.hash(id, version, txTime, txId);
              // CHECKSTYLE:ON
          }
      }
      ```

   1. `QldbRevision.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import com.amazon.ion.IonBlob;
      import com.amazon.ion.IonStruct;
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import software.amazon.qldb.tutorial.Constants;
      import software.amazon.qldb.tutorial.Verifier;
      
      import java.io.IOException;
      import java.util.Arrays;
      import java.util.Objects;
      
      /**
       * Represents a QldbRevision including both user data and metadata.
       */
      public final class QldbRevision {
          private static final Logger log = LoggerFactory.getLogger(QldbRevision.class);
      
          private final BlockAddress blockAddress;
          private final RevisionMetadata metadata;
          private final byte[] hash;
          private final byte[] dataHash;
          private final IonStruct data;
      
          @JsonCreator
          public QldbRevision(@JsonProperty("blockAddress") final BlockAddress blockAddress,
                              @JsonProperty("metadata") final RevisionMetadata metadata,
                              @JsonProperty("hash") final byte[] hash,
                              @JsonProperty("dataHash") final byte[] dataHash,
                              @JsonProperty("data") final IonStruct data) {
              this.blockAddress = blockAddress;
              this.metadata = metadata;
              this.hash = hash;
              this.dataHash = dataHash;
              this.data = data;
          }
      
          /**
           * Gets the unique ID of a QLDB document.
           *
           * @return the {@link BlockAddress} object.
           */
          public BlockAddress getBlockAddress() {
              return blockAddress;
          }
      
          /**
           * Gets the metadata of the revision.
           *
           * @return the {@link RevisionMetadata} object.
           */
          public RevisionMetadata getMetadata() {
              return metadata;
          }
      
          /**
           * Gets the SHA-256 hash value of the revision.
           * This is equivalent to the hash of the revision metadata and data.
           *
           * @return the byte array representing the hash.
           */
          public byte[] getHash() {
              return hash;
          }
      
          /**
           * Gets the SHA-256 hash value of the data portion of the revision.
           * This is only present if the revision is redacted.
           *
           * @return the byte array representing the hash.
           */
          public byte[] getDataHash() {
              return dataHash;
          }
      
          /**
           * Gets the revision data.
           *
           * @return the revision data.
           */
          public IonStruct getData() {
              return data;
          }
      
          /**
           * Returns true if the revision has been redacted.
           * @return a boolean value representing the redaction status
           * of this revision.
           */
          public Boolean isRedacted() {
              return dataHash != null;
          }
      
          /**
           * Constructs a new {@link QldbRevision} from an {@link IonStruct}.
           *
           * The specified {@link IonStruct} must include the following fields
           *
           * - blockAddress -- a {@link BlockAddress},
           * - metadata -- a {@link RevisionMetadata},
           * - hash -- the revision's hash calculated by QLDB,
           * - dataHash -- the user data's hash calculated by QLDB (only present if revision is redacted),
           * - data -- an {@link IonStruct} containing user data in the document.
           *
           * If any of these fields are missing or are malformed, then throws {@link IllegalArgumentException}.
           *
           * If the document hash calculated from the members of the specified {@link IonStruct} does not match
           * the hash member of the {@link IonStruct} then throws {@link IllegalArgumentException}.
           *
           * @param ionStruct
           *              The {@link IonStruct} that contains a {@link QldbRevision} object.
           * @return the converted {@link QldbRevision} object.
           * @throws IOException if failed to parse parameter {@link IonStruct}.
           */
          public static QldbRevision fromIon(final IonStruct ionStruct) throws IOException {
              try {
                  BlockAddress blockAddress = Constants.MAPPER.readValue(ionStruct.get("blockAddress"), BlockAddress.class);
                  IonBlob revisionHash = (IonBlob) ionStruct.get("hash");
                  IonStruct metadataStruct = (IonStruct) ionStruct.get("metadata");
                  IonStruct data = ionStruct.get("data") == null || ionStruct.get("data").isNullValue() ?
                      null : (IonStruct) ionStruct.get("data");
                  IonBlob dataHash = ionStruct.get("dataHash") == null || ionStruct.get("dataHash").isNullValue() ?
                      null : (IonBlob) ionStruct.get("dataHash");
                  if (revisionHash == null || metadataStruct == null) {
                      throw new IllegalArgumentException("Document is missing required fields");
                  }
                  byte[] dataHashBytes = dataHash != null ? dataHash.getBytes() : QldbIonUtils.hashIonValue(data);
                  verifyRevisionHash(metadataStruct, dataHashBytes, revisionHash.getBytes());
                  RevisionMetadata metadata = RevisionMetadata.fromIon(metadataStruct);
                  return new QldbRevision(
                          blockAddress,
                          metadata,
                          revisionHash.getBytes(),
                          dataHash != null ? dataHash.getBytes() : null,
                          data
                  );
              } catch (ClassCastException e) {
                  log.error("Failed to parse ion document");
                  throw new IllegalArgumentException("Document members are not of the correct type", e);
              }
          }
      
          /**
           * Converts a {@link QldbRevision} object to string.
           *
           * @return the string representation of the {@link QldbRevision} object.
           */
          @Override
          public String toString() {
              return "QldbRevision{" +
                      "blockAddress=" + blockAddress +
                      ", metadata=" + metadata +
                      ", hash=" + Arrays.toString(hash) +
                      ", dataHash=" + Arrays.toString(dataHash) +
                      ", data=" + data +
                      '}';
          }
      
          /**
           * Check whether two {@link QldbRevision} objects are equivalent.
           *
           * @return {@code true} if the two objects are equal, {@code false} otherwise.
           */
          @Override
          public boolean equals(final Object o) {
              if (this == o) {
                  return true;
              }
              if (!(o instanceof QldbRevision)) {
                  return false;
              }
              final QldbRevision that = (QldbRevision) o;
              return Objects.equals(getBlockAddress(), that.getBlockAddress())
                      && Objects.equals(getMetadata(), that.getMetadata())
                      && Arrays.equals(getHash(), that.getHash())
                      && Arrays.equals(getDataHash(), that.getDataHash())
                      && Objects.equals(getData(), that.getData());
          }
      
          /**
           * Create a hash code for the {@link QldbRevision} object.
           *
           * @return the hash code.
           */
          @Override
          public int hashCode() {
              // CHECKSTYLE:OFF - Disabling as we are generating a hashCode of multiple properties.
              int result = Objects.hash(blockAddress, metadata, data);
              // CHECKSTYLE:ON
              result = 31 * result + Arrays.hashCode(hash);
              return result;
          }
      
          /**
           * Throws an IllegalArgumentException if the hash of the revision data and metadata
           * does not match the hash provided by QLDB with the revision.
           */
          public void verifyRevisionHash() {
              // Certain internal-only system revisions only contain a hash which cannot be
              // further computed. However, these system hashes still participate to validate
              // the journal block. User revisions will always contain values for all fields
              // and can therefore have their hash computed.
              if (blockAddress == null && metadata == null && data == null && dataHash == null) {
                  return;
              }
      
              try {
                  IonStruct metadataIon = (IonStruct) Constants.MAPPER.writeValueAsIonValue(metadata);
                  byte[] dataHashBytes = isRedacted() ? dataHash : QldbIonUtils.hashIonValue(data);
                  verifyRevisionHash(metadataIon, dataHashBytes, hash);
              } catch (IOException e) {
                  throw new IllegalArgumentException("Could not encode revision metadata to ion.", e);
              }
          }
      
          private static void verifyRevisionHash(IonStruct metadata, byte[] dataHash, byte[] expectedHash) {
              byte[] metadataHash = QldbIonUtils.hashIonValue(metadata);
              byte[] candidateHash = Verifier.dot(metadataHash, dataHash);
              if (!Arrays.equals(candidateHash, expectedHash)) {
                  throw new IllegalArgumentException("Hash entry of QLDB revision and computed hash "
                          + "of QLDB revision do not match");
              }
          }
      }
      ```

   1. `IonLocalDateDeserializer.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.amazon.ion.Timestamp;
      import com.fasterxml.jackson.core.JsonParser;
      import com.fasterxml.jackson.databind.DeserializationContext;
      import com.fasterxml.jackson.databind.JsonDeserializer;
      
      import java.io.IOException;
      import java.time.LocalDate;
      
      /**
       * Deserializes [java.time.LocalDate] from Ion.
       */
      public class IonLocalDateDeserializer extends JsonDeserializer<LocalDate> {
      
          @Override
          public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
              return timestampToLocalDate((Timestamp) jp.getEmbeddedObject());
          }
      
          private LocalDate timestampToLocalDate(Timestamp timestamp) {
              return LocalDate.of(timestamp.getYear(), timestamp.getMonth(), timestamp.getDay());
          }
      }
      ```

   1. `IonLocalDateSerializer.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.model;
      
      import com.amazon.ion.Timestamp;
      import com.fasterxml.jackson.core.JsonGenerator;
      import com.fasterxml.jackson.databind.SerializerProvider;
      import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
      import com.fasterxml.jackson.dataformat.ion.IonGenerator;
      
      import java.io.IOException;
      import java.time.LocalDate;
      
      /**
       * Serializes [java.time.LocalDate] to Ion.
       */
      public class IonLocalDateSerializer extends StdScalarSerializer<LocalDate> {
      
          public IonLocalDateSerializer() {
              super(LocalDate.class);
          }
      
          @Override
          public void serialize(LocalDate date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
              Timestamp timestamp = Timestamp.forDay(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
              ((IonGenerator) jsonGenerator).writeValue(timestamp);
          }
      }
      ```

1. Esaminate il seguente file (`SampleData.java`), che rappresenta i dati di esempio che inserite nelle tabelle. `vehicle-registration`

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial.model;
   
   import com.amazon.ion.IonString;
   import com.amazon.ion.IonStruct;
   import com.amazon.ion.IonValue;
   import java.io.IOException;
   import java.math.BigDecimal;
   import java.text.ParseException;
   import java.time.LocalDate;
   import java.time.format.DateTimeFormatter;
   import java.util.ArrayList;
   import java.util.Arrays;
   import java.util.Collections;
   import java.util.List;
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.ConnectToLedger;
   import software.amazon.qldb.tutorial.Constants;
   import software.amazon.qldb.tutorial.qldb.DmlResultDocument;
   import software.amazon.qldb.tutorial.qldb.QldbRevision;
   
   /**
    * Sample domain objects for use throughout this tutorial.
    */
   public final class SampleData {
       public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
   
       public static final List<VehicleRegistration> REGISTRATIONS = Collections.unmodifiableList(Arrays.asList(
               new VehicleRegistration("1N4AL11D75C109151", "LEWISR261LL", "WA", "Seattle",
                       BigDecimal.valueOf(90.25), convertToLocalDate("2017-08-21"), convertToLocalDate("2020-05-11"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("KM8SRDHF6EU074761", "CA762X", "WA", "Kent",
                       BigDecimal.valueOf(130.75), convertToLocalDate("2017-09-14"), convertToLocalDate("2020-06-25"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("3HGGK5G53FM761765", "CD820Z", "WA", "Everett",
                       BigDecimal.valueOf(442.30), convertToLocalDate("2011-03-17"), convertToLocalDate("2021-03-24"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("1HVBBAANXWH544237", "LS477D", "WA", "Tacoma",
                       BigDecimal.valueOf(42.20), convertToLocalDate("2011-10-26"), convertToLocalDate("2023-09-25"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("1C4RJFAG0FC625797", "TH393F", "WA", "Olympia",
                       BigDecimal.valueOf(30.45), convertToLocalDate("2013-09-02"), convertToLocalDate("2024-03-19"),
                       new Owners(new Owner(null), Collections.emptyList()))
       ));
   
       public static final List<Vehicle> VEHICLES = Collections.unmodifiableList(Arrays.asList(
               new Vehicle("1N4AL11D75C109151", "Sedan", 2011,  "Audi", "A5", "Silver"),
               new Vehicle("KM8SRDHF6EU074761", "Sedan", 2015, "Tesla", "Model S", "Blue"),
               new Vehicle("3HGGK5G53FM761765", "Motorcycle", 2011, "Ducati", "Monster 1200", "Yellow"),
               new Vehicle("1HVBBAANXWH544237", "Semi", 2009, "Ford", "F 150", "Black"),
               new Vehicle("1C4RJFAG0FC625797", "Sedan", 2019, "Mercedes", "CLK 350", "White")
       ));
   
       public static final List<Person> PEOPLE = Collections.unmodifiableList(Arrays.asList(
               new Person("Raul", "Lewis", convertToLocalDate("1963-08-19"),
                       "LEWISR261LL", "Driver License",  "1719 University Street, Seattle, WA, 98109"),
               new Person("Brent", "Logan", convertToLocalDate("1967-07-03"),
                       "LOGANB486CG", "Driver License", "43 Stockert Hollow Road, Everett, WA, 98203"),
               new Person("Alexis", "Pena", convertToLocalDate("1974-02-10"),
                       "744 849 301", "SSN", "4058 Melrose Street, Spokane Valley, WA, 99206"),
               new Person("Melvin", "Parker", convertToLocalDate("1976-05-22"),
                       "P626-168-229-765", "Passport", "4362 Ryder Avenue, Seattle, WA, 98101"),
               new Person("Salvatore", "Spencer", convertToLocalDate("1997-11-15"),
                       "S152-780-97-415-0", "Passport", "4450 Honeysuckle Lane, Seattle, WA, 98101")
       ));
   
       public static final List<DriversLicense> LICENSES = Collections.unmodifiableList(Arrays.asList(
               new DriversLicense(null, "LEWISR261LL", "Learner",
                       convertToLocalDate("2016-12-20"), convertToLocalDate("2020-11-15")),
               new DriversLicense(null, "LOGANB486CG", "Probationary",
                       convertToLocalDate("2016-04-06"), convertToLocalDate("2020-11-15")),
               new DriversLicense(null, "744 849 301", "Full",
                       convertToLocalDate("2017-12-06"), convertToLocalDate("2022-10-15")),
               new DriversLicense(null, "P626-168-229-765", "Learner",
                       convertToLocalDate("2017-08-16"), convertToLocalDate("2021-11-15")),
               new DriversLicense(null, "S152-780-97-415-0", "Probationary",
                       convertToLocalDate("2015-08-15"), convertToLocalDate("2021-08-21"))
       ));
   
       private SampleData() { }
   
       /**
        * Converts a date string with the format 'yyyy-MM-dd' into a {@link java.util.Date} object.
        *
        * @param date
        *              The date string to convert.
        * @return {@link java.time.LocalDate} or null if there is a {@link ParseException}
        */
       public static synchronized LocalDate convertToLocalDate(String date) {
           return LocalDate.parse(date, DATE_TIME_FORMAT);
       }
   
       /**
        * Convert the result set into a list of IonValues.
        *
        * @param result
        *              The result set to convert.
        * @return a list of IonValues.
        */
       public static List<IonValue> toIonValues(Result result) {
           final List<IonValue> valueList = new ArrayList<>();
           result.iterator().forEachRemaining(valueList::add);
           return valueList;
       }
   
       /**
        * Get the document ID of a particular document.
        *
        * @param txn
        *              A transaction executor object.
        * @param tableName
        *              Name of the table containing the document.
        * @param identifier
        *              The identifier used to narrow down the search.
        * @param value
        *              Value of the identifier.
        * @return the list of document IDs in the result set.
        */
       public static String getDocumentId(final TransactionExecutor txn, final String tableName,
                                          final String identifier, final String value) {
           try {
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(value));
               final String query = String.format("SELECT metadata.id FROM _ql_committed_%s AS p WHERE p.data.%s = ?",
                       tableName, identifier);
               Result result = txn.execute(query, parameters);
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to retrieve document ID using " + value);
               }
               return getStringValueOfStructField((IonStruct) result.iterator().next(), "id");
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Get the document by ID.
        *
        * @param tableName
        *              Name of the table to insert documents into.
        * @param documentId
        *              The unique ID of a document in the Person table.
        * @return a {@link QldbRevision} object.
        * @throws IllegalStateException if failed to convert parameter into {@link IonValue}.
        */
       public static QldbRevision getDocumentById(String tableName, String documentId) {
           try {
               final IonValue ionValue = Constants.MAPPER.writeValueAsIonValue(documentId);
               Result result = ConnectToLedger.getDriver().execute(txn -> {
                   return txn.execute("SELECT c.* FROM _ql_committed_" + tableName + " AS c BY docId "
                                      + "WHERE docId = ?", ionValue);
               });
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to retrieve document by id " + documentId + " in table " + tableName);
               }
               return Constants.MAPPER.readValue(result.iterator().next(), QldbRevision.class);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Return a list of modified document IDs as strings from a DML {@link Result}.
        *
        * @param result
        *              The result set from a DML operation.
        * @return the list of document IDs modified by the operation.
        */
       public static List<String> getDocumentIdsFromDmlResult(final Result result) {
           final List<String> strings = new ArrayList<>();
           result.iterator().forEachRemaining(row -> strings.add(getDocumentIdFromDmlResultDocument(row)));
           return strings;
       }
   
       /**
        * Convert the given DML result row's document ID to string.
        *
        * @param dmlResultDocument
        *              The {@link IonValue} representing the results of a DML operation.
        * @return a string of document ID.
        */
       public static String getDocumentIdFromDmlResultDocument(final IonValue dmlResultDocument) {
           try {
               DmlResultDocument result = Constants.MAPPER.readValue(dmlResultDocument, DmlResultDocument.class);
               return result.getDocumentId();
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Get the String value of a given {@link IonStruct} field name.
        * @param struct the {@link IonStruct} from which to get the value.
        * @param fieldName the name of the field from which to get the value.
        * @return the String value of the field within the given {@link IonStruct}.
        */
       public static String getStringValueOfStructField(final IonStruct struct, final String fieldName) {
           return ((IonString) struct.get(fieldName)).stringValue();
       }
   
       /**
        * Return a copy of the given driver's license with updated person Id.
        *
        * @param oldLicense
        *              The old driver's license to update.
        * @param personId
        *              The PersonId of the driver.
        * @return the updated {@link DriversLicense}.
        */
       public static DriversLicense updatePersonIdDriversLicense(final DriversLicense oldLicense, final String personId) {
           return new DriversLicense(personId, oldLicense.getLicenseNumber(), oldLicense.getLicenseType(),
                   oldLicense.getValidFromDate(), oldLicense.getValidToDate());
       }
   
       /**
        * Return a copy of the given vehicle registration with updated person Id.
        *
        * @param oldRegistration
        *              The old vehicle registration to update.
        * @param personId
        *              The PersonId of the driver.
        * @return the updated {@link VehicleRegistration}.
        */
       public static VehicleRegistration updateOwnerVehicleRegistration(final VehicleRegistration oldRegistration,
                                                                        final String personId) {
           return new VehicleRegistration(oldRegistration.getVin(), oldRegistration.getLicensePlateNumber(),
                   oldRegistration.getState(), oldRegistration.getCity(), oldRegistration.getPendingPenaltyTicketAmount(),
                   oldRegistration.getValidFromDate(), oldRegistration.getValidToDate(),
                   new Owners(new Owner(personId), Collections.emptyList()));
       }
   }
   ```

------
#### [ 1.x ]

**Importante**  
Per il pacchetto Amazon Ion, devi utilizzare lo spazio dei nomi `com.amazon.ion` nella tua applicazione. AWS SDK per Java Dipende da un altro pacchetto Ion nello spazio dei nomi`software.amazon.ion`, ma si tratta di un pacchetto legacy non compatibile con il driver QLDB.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial.model;
   
   import com.amazon.ion.IonString;
   import com.amazon.ion.IonStruct;
   import com.amazon.ion.IonValue;
   import software.amazon.qldb.QldbSession;
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.Constants;
   import software.amazon.qldb.tutorial.qldb.DmlResultDocument;
   import software.amazon.qldb.tutorial.qldb.QldbRevision;
   
   import java.io.IOException;
   
   import java.math.BigDecimal;
   import java.text.ParseException;
   import java.time.LocalDate;
   import java.time.format.DateTimeFormatter;
   import java.util.ArrayList;
   import java.util.Arrays;
   import java.util.Collections;
   import java.util.List;
   
   /**
    * Sample domain objects for use throughout this tutorial.
    */
   public final class SampleData {
       public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
   
       public static final List<VehicleRegistration> REGISTRATIONS = Collections.unmodifiableList(Arrays.asList(
               new VehicleRegistration("1N4AL11D75C109151", "LEWISR261LL", "WA", "Seattle",
                       BigDecimal.valueOf(90.25), convertToLocalDate("2017-08-21"), convertToLocalDate("2020-05-11"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("KM8SRDHF6EU074761", "CA762X", "WA", "Kent",
                       BigDecimal.valueOf(130.75), convertToLocalDate("2017-09-14"), convertToLocalDate("2020-06-25"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("3HGGK5G53FM761765", "CD820Z", "WA", "Everett",
                       BigDecimal.valueOf(442.30), convertToLocalDate("2011-03-17"), convertToLocalDate("2021-03-24"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("1HVBBAANXWH544237", "LS477D", "WA", "Tacoma",
                       BigDecimal.valueOf(42.20), convertToLocalDate("2011-10-26"), convertToLocalDate("2023-09-25"),
                       new Owners(new Owner(null), Collections.emptyList())),
               new VehicleRegistration("1C4RJFAG0FC625797", "TH393F", "WA", "Olympia",
                       BigDecimal.valueOf(30.45), convertToLocalDate("2013-09-02"), convertToLocalDate("2024-03-19"),
                       new Owners(new Owner(null), Collections.emptyList()))
       ));
   
       public static final List<Vehicle> VEHICLES = Collections.unmodifiableList(Arrays.asList(
               new Vehicle("1N4AL11D75C109151", "Sedan", 2011,  "Audi", "A5", "Silver"),
               new Vehicle("KM8SRDHF6EU074761", "Sedan", 2015, "Tesla", "Model S", "Blue"),
               new Vehicle("3HGGK5G53FM761765", "Motorcycle", 2011, "Ducati", "Monster 1200", "Yellow"),
               new Vehicle("1HVBBAANXWH544237", "Semi", 2009, "Ford", "F 150", "Black"),
               new Vehicle("1C4RJFAG0FC625797", "Sedan", 2019, "Mercedes", "CLK 350", "White")
       ));
   
       public static final List<Person> PEOPLE = Collections.unmodifiableList(Arrays.asList(
               new Person("Raul", "Lewis", convertToLocalDate("1963-08-19"),
                       "LEWISR261LL", "Driver License",  "1719 University Street, Seattle, WA, 98109"),
               new Person("Brent", "Logan", convertToLocalDate("1967-07-03"),
                       "LOGANB486CG", "Driver License", "43 Stockert Hollow Road, Everett, WA, 98203"),
               new Person("Alexis", "Pena", convertToLocalDate("1974-02-10"),
                       "744 849 301", "SSN", "4058 Melrose Street, Spokane Valley, WA, 99206"),
               new Person("Melvin", "Parker", convertToLocalDate("1976-05-22"),
                       "P626-168-229-765", "Passport", "4362 Ryder Avenue, Seattle, WA, 98101"),
               new Person("Salvatore", "Spencer", convertToLocalDate("1997-11-15"),
                       "S152-780-97-415-0", "Passport", "4450 Honeysuckle Lane, Seattle, WA, 98101")
       ));
   
       public static final List<DriversLicense> LICENSES = Collections.unmodifiableList(Arrays.asList(
               new DriversLicense(null, "LEWISR261LL", "Learner",
                       convertToLocalDate("2016-12-20"), convertToLocalDate("2020-11-15")),
               new DriversLicense(null, "LOGANB486CG", "Probationary",
                       convertToLocalDate("2016-04-06"), convertToLocalDate("2020-11-15")),
               new DriversLicense(null, "744 849 301", "Full",
                       convertToLocalDate("2017-12-06"), convertToLocalDate("2022-10-15")),
               new DriversLicense(null, "P626-168-229-765", "Learner",
                       convertToLocalDate("2017-08-16"), convertToLocalDate("2021-11-15")),
               new DriversLicense(null, "S152-780-97-415-0", "Probationary",
                       convertToLocalDate("2015-08-15"), convertToLocalDate("2021-08-21"))
       ));
   
       private SampleData() { }
   
       /**
        * Converts a date string with the format 'yyyy-MM-dd' into a {@link java.util.Date} object.
        *
        * @param date
        *              The date string to convert.
        * @return {@link LocalDate} or null if there is a {@link ParseException}
        */
       public static synchronized LocalDate convertToLocalDate(String date) {
           return LocalDate.parse(date, DATE_TIME_FORMAT);
       }
   
       /**
        * Convert the result set into a list of IonValues.
        *
        * @param result
        *              The result set to convert.
        * @return a list of IonValues.
        */
       public static List<IonValue> toIonValues(Result result) {
           final List<IonValue> valueList = new ArrayList<>();
           result.iterator().forEachRemaining(valueList::add);
           return valueList;
       }
   
       /**
        * Get the document ID of a particular document.
        *
        * @param txn
        *              A transaction executor object.
        * @param tableName
        *              Name of the table containing the document.
        * @param identifier
        *              The identifier used to narrow down the search.
        * @param value
        *              Value of the identifier.
        * @return the list of document IDs in the result set.
        */
       public static String getDocumentId(final TransactionExecutor txn, final String tableName,
                                          final String identifier, final String value) {
           try {
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(value));
               final String query = String.format("SELECT metadata.id FROM _ql_committed_%s AS p WHERE p.data.%s = ?",
                       tableName, identifier);
               Result result = txn.execute(query, parameters);
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to retrieve document ID using " + value);
               }
               return getStringValueOfStructField((IonStruct) result.iterator().next(), "id");
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Get the document by ID.
        *
        * @param qldbSession
        *              A QLDB session.
        * @param tableName
        *              Name of the table to insert documents into.
        * @param documentId
        *              The unique ID of a document in the Person table.
        * @return a {@link QldbRevision} object.
        * @throws IllegalStateException if failed to convert parameter into {@link IonValue}.
        */
       public static QldbRevision getDocumentById(QldbSession qldbSession, String tableName, String documentId) {
           try {
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(documentId));
               final String query = String.format("SELECT c.* FROM _ql_committed_%s AS c BY docId WHERE docId = ?", tableName);
               Result result = qldbSession.execute(query, parameters);
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to retrieve document by id " + documentId + " in table " + tableName);
               }
               return Constants.MAPPER.readValue(result.iterator().next(), QldbRevision.class);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Return a list of modified document IDs as strings from a DML {@link Result}.
        *
        * @param result
        *              The result set from a DML operation.
        * @return the list of document IDs modified by the operation.
        */
       public static List<String> getDocumentIdsFromDmlResult(final Result result) {
           final List<String> strings = new ArrayList<>();
           result.iterator().forEachRemaining(row -> strings.add(getDocumentIdFromDmlResultDocument(row)));
           return strings;
       }
   
       /**
        * Convert the given DML result row's document ID to string.
        *
        * @param dmlResultDocument
        *              The {@link IonValue} representing the results of a DML operation.
        * @return a string of document ID.
        */
       public static String getDocumentIdFromDmlResultDocument(final IonValue dmlResultDocument) {
           try {
               DmlResultDocument result = Constants.MAPPER.readValue(dmlResultDocument, DmlResultDocument.class);
               return result.getDocumentId();
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Get the String value of a given {@link IonStruct} field name.
        * @param struct the {@link IonStruct} from which to get the value.
        * @param fieldName the name of the field from which to get the value.
        * @return the String value of the field within the given {@link IonStruct}.
        */
       public static String getStringValueOfStructField(final IonStruct struct, final String fieldName) {
           return ((IonString) struct.get(fieldName)).stringValue();
       }
   
       /**
        * Return a copy of the given driver's license with updated person Id.
        *
        * @param oldLicense
        *              The old driver's license to update.
        * @param personId
        *              The PersonId of the driver.
        * @return the updated {@link DriversLicense}.
        */
       public static DriversLicense updatePersonIdDriversLicense(final DriversLicense oldLicense, final String personId) {
           return new DriversLicense(personId, oldLicense.getLicenseNumber(), oldLicense.getLicenseType(),
                   oldLicense.getValidFromDate(), oldLicense.getValidToDate());
       }
   
       /**
        * Return a copy of the given vehicle registration with updated person Id.
        *
        * @param oldRegistration
        *              The old vehicle registration to update.
        * @param personId
        *              The PersonId of the driver.
        * @return the updated {@link VehicleRegistration}.
        */
       public static VehicleRegistration updateOwnerVehicleRegistration(final VehicleRegistration oldRegistration,
                                                                        final String personId) {
           return new VehicleRegistration(oldRegistration.getVin(), oldRegistration.getLicensePlateNumber(),
                   oldRegistration.getState(), oldRegistration.getCity(), oldRegistration.getPendingPenaltyTicketAmount(),
                   oldRegistration.getValidFromDate(), oldRegistration.getValidToDate(),
                   new Owners(new Owner(personId), Collections.emptyList()));
       }
   }
   ```

------
**Nota**  
Questa classe utilizza le librerie Ion per fornire metodi di supporto che convertono i dati da e verso il formato Ion.
Il `getDocumentId` metodo esegue una query su una tabella con il prefisso`_ql_committed_`. Si tratta di un prefisso riservato che indica che si desidera interrogare la *visualizzazione confermata di una tabella*. In questa visualizzazione, i dati sono annidati nel `data` campo e i metadati sono annidati nel campo. `metadata`

1. Compila ed esegui il seguente programma (`CreateTable.java`) per creare le tabelle menzionate in precedenza.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Create tables in a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class CreateTable {
       public static final Logger log = LoggerFactory.getLogger(CreateTable.class);
   
       private CreateTable() { }
   
       /**
        * Registrations, vehicles, owners, and licenses tables being created in a single transaction.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param tableName
        *              Name of the table to be created.
        * @return the number of tables created.
        */
       public static int createTable(final TransactionExecutor txn, final String tableName) {
           log.info("Creating the '{}' table...", tableName);
           final String createTable = String.format("CREATE TABLE %s", tableName);
           final Result result = txn.execute(createTable);
           log.info("{} table created successfully.", tableName);
           return SampleData.toIonValues(result).size();
       }
   
       public static void main(final String... args) {
           ConnectToLedger.getDriver().execute(txn -> {
               createTable(txn, Constants.DRIVERS_LICENSE_TABLE_NAME);
               createTable(txn, Constants.PERSON_TABLE_NAME);
               createTable(txn, Constants.VEHICLE_TABLE_NAME);
               createTable(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME);
           });
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Create tables in a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class CreateTable {
       public static final Logger log = LoggerFactory.getLogger(CreateTable.class);
   
       private CreateTable() { }
   
       /**
        * Registrations, vehicles, owners, and licenses tables being created in a single transaction.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param tableName
        *              Name of the table to be created.
        * @return the number of tables created.
        */
       public static int createTable(final TransactionExecutor txn, final String tableName) {
           log.info("Creating the '{}' table...", tableName);
           final String createTable = String.format("CREATE TABLE %s", tableName);
           final Result result = txn.execute(createTable);
           log.info("{} table created successfully.", tableName);
           return SampleData.toIonValues(result).size();
       }
   
       public static void main(final String... args) {
           ConnectToLedger.getDriver().execute(txn -> {
               createTable(txn, Constants.DRIVERS_LICENSE_TABLE_NAME);
               createTable(txn, Constants.PERSON_TABLE_NAME);
               createTable(txn, Constants.VEHICLE_TABLE_NAME);
               createTable(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME);
           }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
       }
   }
   ```

------
**Nota**  
Questo programma dimostra come passare un `TransactionExecutor` lambda al metodo. `execute` In questo esempio, si eseguono più istruzioni `CREATE TABLE` PartiQL in una singola transazione utilizzando un'espressione lambda.  
Il `execute` metodo avvia implicitamente una transazione, esegue tutte le istruzioni in lambda e quindi esegue automaticamente il commit della transazione.

1. Compila ed esegui il seguente programma (`CreateIndex.java`) per creare indici sulle tabelle, come descritto in precedenza.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Create indexes on tables in a particular ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class CreateIndex {
       public static final Logger log = LoggerFactory.getLogger(CreateIndex.class);
   
       private CreateIndex() { }
   
       /**
        * In this example, create indexes for registrations and vehicles tables.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param tableName
        *              Name of the table to be created.
        * @param indexAttribute
        *              The index attribute to use.
        * @return the number of tables created.
        */
       public static int createIndex(final TransactionExecutor txn, final String tableName, final String indexAttribute) {
           log.info("Creating an index on {}...", indexAttribute);
           final String createIndex = String.format("CREATE INDEX ON %s (%s)", tableName, indexAttribute);
           final Result r = txn.execute(createIndex);
           return SampleData.toIonValues(r).size();
       }
   
       public static void main(final String... args) {
           ConnectToLedger.getDriver().execute(txn -> {
               createIndex(txn, Constants.PERSON_TABLE_NAME, Constants.PERSON_GOV_ID_INDEX_NAME);
               createIndex(txn, Constants.VEHICLE_TABLE_NAME, Constants.VIN_INDEX_NAME);
               createIndex(txn, Constants.DRIVERS_LICENSE_TABLE_NAME, Constants.DRIVER_LICENSE_NUMBER_INDEX_NAME);
               createIndex(txn, Constants.DRIVERS_LICENSE_TABLE_NAME, Constants.DRIVER_LICENSE_PERSONID_INDEX_NAME);
               createIndex(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME, Constants.VIN_INDEX_NAME);
               createIndex(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                       Constants.VEHICLE_REGISTRATION_LICENSE_PLATE_NUMBER_INDEX_NAME);
           });
           log.info("Indexes created successfully!");
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Create indexes on tables in a particular ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class CreateIndex {
       public static final Logger log = LoggerFactory.getLogger(CreateIndex.class);
   
       private CreateIndex() { }
   
       /**
        * In this example, create indexes for registrations and vehicles tables.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param tableName
        *              Name of the table to be created.
        * @param indexAttribute
        *              The index attribute to use.
        * @return the number of tables created.
        */
       public static int createIndex(final TransactionExecutor txn, final String tableName, final String indexAttribute) {
           log.info("Creating an index on {}...", indexAttribute);
           final String createIndex = String.format("CREATE INDEX ON %s (%s)", tableName, indexAttribute);
           final Result r = txn.execute(createIndex);
           return SampleData.toIonValues(r).size();
       }
   
       public static void main(final String... args) {
           ConnectToLedger.getDriver().execute(txn -> {
               createIndex(txn, Constants.PERSON_TABLE_NAME, Constants.PERSON_GOV_ID_INDEX_NAME);
               createIndex(txn, Constants.VEHICLE_TABLE_NAME, Constants.VIN_INDEX_NAME);
               createIndex(txn, Constants.DRIVERS_LICENSE_TABLE_NAME, Constants.DRIVER_LICENSE_NUMBER_INDEX_NAME);
               createIndex(txn, Constants.DRIVERS_LICENSE_TABLE_NAME, Constants.DRIVER_LICENSE_PERSONID_INDEX_NAME);
               createIndex(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME, Constants.VIN_INDEX_NAME);
               createIndex(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                       Constants.VEHICLE_REGISTRATION_LICENSE_PLATE_NUMBER_INDEX_NAME);
           }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
           log.info("Indexes created successfully!");
       }
   }
   ```

------

1. Compilate ed eseguite il seguente programma (`InsertDocument.java`) per inserire i dati di esempio nelle tabelle.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.List;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import com.amazon.ion.IonValue;
   
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.DriversLicense;
   import software.amazon.qldb.tutorial.model.SampleData;
   import software.amazon.qldb.tutorial.model.VehicleRegistration;
   
   /**
    * Insert documents into a table in a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class InsertDocument {
       public static final Logger log = LoggerFactory.getLogger(InsertDocument.class);
   
       private InsertDocument() { }
   
       /**
        * Insert the given list of documents into the specified table and return the document IDs of the inserted documents.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param tableName
        *              Name of the table to insert documents into.
        * @param documents
        *              List of documents to insert into the specified table.
        * @return a list of document IDs.
        * @throws IllegalStateException if failed to convert documents into an {@link IonValue}.
        */
       public static List<String> insertDocuments(final TransactionExecutor txn, final String tableName,
                                                  final List documents) {
           log.info("Inserting some documents in the {} table...", tableName);
           try {
               final String query = String.format("INSERT INTO %s ?", tableName);
               final IonValue ionDocuments = Constants.MAPPER.writeValueAsIonValue(documents);
   
               return SampleData.getDocumentIdsFromDmlResult(txn.execute(query, ionDocuments));
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Update PersonIds in driver's licenses and in vehicle registrations using document IDs.
        *
        * @param documentIds
        *              List of document IDs representing the PersonIds in DriversLicense and PrimaryOwners in VehicleRegistration.
        * @param licenses
        *              List of driver's licenses to update.
        * @param registrations
        *              List of registrations to update.
        */
       public static void updatePersonId(final List<String> documentIds, final List<DriversLicense> licenses,
                                         final List<VehicleRegistration> registrations) {
           for (int i = 0; i < documentIds.size(); ++i) {
               DriversLicense license = SampleData.LICENSES.get(i);
               VehicleRegistration registration = SampleData.REGISTRATIONS.get(i);
               licenses.add(SampleData.updatePersonIdDriversLicense(license, documentIds.get(i)));
               registrations.add(SampleData.updateOwnerVehicleRegistration(registration, documentIds.get(i)));
           }
       }
   
       public static void main(final String... args) {
           final List<DriversLicense> newDriversLicenses = new ArrayList<>();
           final List<VehicleRegistration> newVehicleRegistrations = new ArrayList<>();
           ConnectToLedger.getDriver().execute(txn -> {
               List<String> documentIds = insertDocuments(txn, Constants.PERSON_TABLE_NAME, SampleData.PEOPLE);
               updatePersonId(documentIds, newDriversLicenses, newVehicleRegistrations);
               insertDocuments(txn, Constants.VEHICLE_TABLE_NAME, SampleData.VEHICLES);
               insertDocuments(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                       Collections.unmodifiableList(newVehicleRegistrations));
               insertDocuments(txn, Constants.DRIVERS_LICENSE_TABLE_NAME,
                       Collections.unmodifiableList(newDriversLicenses));
           });
           log.info("Documents inserted successfully!");
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonValue;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.QldbSession;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.DriversLicense;
   import software.amazon.qldb.tutorial.model.SampleData;
   import software.amazon.qldb.tutorial.model.VehicleRegistration;
   
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.List;
   
   /**
    * Insert documents into a table in a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class InsertDocument {
       public static final Logger log = LoggerFactory.getLogger(InsertDocument.class);
   
       private InsertDocument() { }
   
       /**
        * Insert the given list of documents into the specified table and return the document IDs of the inserted documents.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param tableName
        *              Name of the table to insert documents into.
        * @param documents
        *              List of documents to insert into the specified table.
        * @return a list of document IDs.
        * @throws IllegalStateException if failed to convert documents into an {@link IonValue}.
        */
       public static List<String> insertDocuments(final TransactionExecutor txn, final String tableName,
                                                  final List documents) {
           log.info("Inserting some documents in the {} table...", tableName);
           try {
               final String statement = String.format("INSERT INTO %s ?", tableName);
               final IonValue ionDocuments = Constants.MAPPER.writeValueAsIonValue(documents);
               final List<IonValue> parameters = Collections.singletonList(ionDocuments);
               return SampleData.getDocumentIdsFromDmlResult(txn.execute(statement, parameters));
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Update PersonIds in driver's licenses and in vehicle registrations using document IDs.
        *
        * @param documentIds
        *              List of document IDs representing the PersonIds in DriversLicense and PrimaryOwners in VehicleRegistration.
        * @param licenses
        *              List of driver's licenses to update.
        * @param registrations
        *              List of registrations to update.
        */
       public static void updatePersonId(final List<String> documentIds, final List<DriversLicense> licenses,
                                         final List<VehicleRegistration> registrations) {
           for (int i = 0; i < documentIds.size(); ++i) {
               DriversLicense license = SampleData.LICENSES.get(i);
               VehicleRegistration registration = SampleData.REGISTRATIONS.get(i);
               licenses.add(SampleData.updatePersonIdDriversLicense(license, documentIds.get(i)));
               registrations.add(SampleData.updateOwnerVehicleRegistration(registration, documentIds.get(i)));
           }
       }
   
       public static void main(final String... args) {
           final List<DriversLicense> newDriversLicenses = new ArrayList<>();
           final List<VehicleRegistration> newVehicleRegistrations = new ArrayList<>();
           ConnectToLedger.getDriver().execute(txn -> {
               List<String> documentIds = insertDocuments(txn, Constants.PERSON_TABLE_NAME, SampleData.PEOPLE);
               updatePersonId(documentIds, newDriversLicenses, newVehicleRegistrations);
               insertDocuments(txn, Constants.VEHICLE_TABLE_NAME, SampleData.VEHICLES);
               insertDocuments(txn, Constants.VEHICLE_REGISTRATION_TABLE_NAME,
                       Collections.unmodifiableList(newVehicleRegistrations));
               insertDocuments(txn, Constants.DRIVERS_LICENSE_TABLE_NAME,
                       Collections.unmodifiableList(newDriversLicenses));
           }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
           log.info("Documents inserted successfully!");
       }
   }
   ```

------
**Nota**  
Questo programma dimostra come chiamare il `execute` metodo con valori parametrizzati. È possibile passare parametri di dati di tipo oltre `IonValue` all'istruzione PartiQL che si desidera eseguire. Utilizzate un punto interrogativo (`?`) come segnaposto variabile nella stringa dell'istruzione.
Se un'`INSERT`istruzione ha esito positivo, restituisce il valore `id` di ogni documento inserito.

Successivamente, è possibile utilizzare `SELECT` le istruzioni per leggere i dati dalle tabelle del `vehicle-registration` registro. Passa a [Passaggio 4: interrogare le tabelle in un libro mastro](getting-started.java.step-4.md).

# Passaggio 4: interrogare le tabelle in un libro mastro
<a name="getting-started.java.step-4"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Dopo aver creato tabelle in un registro Amazon QLDB e averle caricate con i dati, puoi eseguire query per rivedere i dati di immatricolazione dei veicoli che hai appena inserito. QLDB [utilizza](ql-reference.md) PartiQL come linguaggio di interrogazione [e Amazon](ion.md) Ion come modello di dati orientato ai documenti.

PartiQL è un linguaggio di query open source compatibile con SQL che è stato esteso per funzionare con Ion. Con PartiQL, puoi inserire, interrogare e gestire i tuoi dati con operatori SQL familiari. Amazon Ion è un superset di JSON. Ion è un formato di dati open source basato su documenti che offre la flessibilità di archiviazione ed elaborazione di dati strutturati, semistrutturati e annidati.

In questo passaggio, si utilizzano `SELECT` le istruzioni per leggere i dati dalle tabelle del registro. `vehicle-registration`

**avvertimento**  
Quando si esegue una query in QLDB senza una ricerca indicizzata, viene richiamata una scansione completa della tabella. PartiQL supporta tali query perché è compatibile con SQL. Tuttavia, *non* eseguire scansioni di tabelle per casi d'uso di produzione in QLDB. Le scansioni delle tabelle possono causare problemi di prestazioni su tabelle di grandi dimensioni, inclusi conflitti di concorrenza e timeout delle transazioni.  
Per evitare le scansioni delle tabelle, è necessario eseguire istruzioni con una clausola di `WHERE` predicato utilizzando un operatore di *uguaglianza* su un campo indicizzato o un ID di documento; ad esempio, o. `WHERE indexedField = 123` `WHERE indexedField IN (456, 789)` Per ulteriori informazioni, consulta [Ottimizzazione delle prestazioni delle query](working.optimize.md).

**Per interrogare le tabelle**
+ Compila ed esegui il seguente programma (`FindVehicles.java`) per interrogare tutti i veicoli registrati con una persona nel tuo registro.

------
#### [ 2.x ]

  ```
  /*
   * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
   * SPDX-License-Identifier: MIT-0
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of this
   * software and associated documentation files (the "Software"), to deal in the Software
   * without restriction, including without limitation the rights to use, copy, modify,
   * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
   * permit persons to whom the Software is furnished to do so.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
   * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  
  package software.amazon.qldb.tutorial;
  
  import java.io.IOException;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import com.amazon.ion.IonValue;
  
  import software.amazon.qldb.Result;
  import software.amazon.qldb.TransactionExecutor;
  import software.amazon.qldb.tutorial.model.Person;
  import software.amazon.qldb.tutorial.model.SampleData;
  
  /**
   * Find all vehicles registered under a person.
   *
   * This code expects that you have AWS credentials setup per:
   * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
   */
  public final class FindVehicles {
      public static final Logger log = LoggerFactory.getLogger(FindVehicles.class);
  
      private FindVehicles() { }
  
      /**
       * Find vehicles registered under a driver using their government ID.
       *
       * @param txn
       *              The {@link TransactionExecutor} for lambda execute.
       * @param govId
       *              The government ID of the owner.
       * @throws IllegalStateException if failed to convert parameters into {@link IonValue}.
       */
      public static void findVehiclesForOwner(final TransactionExecutor txn, final String govId) {
          try {
              final String documentId = Person.getDocumentIdByGovId(txn, govId);
              final String query = "SELECT v FROM Vehicle AS v INNER JOIN VehicleRegistration AS r "
                      + "ON v.VIN = r.VIN WHERE r.Owners.PrimaryOwner.PersonId = ?";
  
              final Result result = txn.execute(query, Constants.MAPPER.writeValueAsIonValue(documentId));
              log.info("List of Vehicles for owner with GovId: {}...", govId);
              ScanTable.printDocuments(result);
          } catch (IOException ioe) {
              throw new IllegalStateException(ioe);
          }
      }
  
      public static void main(final String... args) {
          final Person person = SampleData.PEOPLE.get(0);
          ConnectToLedger.getDriver().execute(txn -> {
              findVehiclesForOwner(txn, person.getGovId());
          });
      }
  }
  ```

------
#### [ 1.x ]

  ```
  /*
   * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   * SPDX-License-Identifier: MIT-0
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of this
   * software and associated documentation files (the "Software"), to deal in the Software
   * without restriction, including without limitation the rights to use, copy, modify,
   * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
   * permit persons to whom the Software is furnished to do so.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
   * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  
  package software.amazon.qldb.tutorial;
  
  import java.io.IOException;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import com.amazon.ion.IonValue;
  
  import software.amazon.qldb.Result;
  import software.amazon.qldb.TransactionExecutor;
  import software.amazon.qldb.tutorial.model.Person;
  import software.amazon.qldb.tutorial.model.SampleData;
  
  /**
   * Find all vehicles registered under a person.
   *
   * This code expects that you have AWS credentials setup per:
   * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
   */
  public final class FindVehicles {
      public static final Logger log = LoggerFactory.getLogger(FindVehicles.class);
  
      private FindVehicles() { }
  
      /**
       * Find vehicles registered under a driver using their government ID.
       *
       * @param txn
       *              The {@link TransactionExecutor} for lambda execute.
       * @param govId
       *              The government ID of the owner.
       * @throws IllegalStateException if failed to convert parameters into {@link IonValue}.
       */
      public static void findVehiclesForOwner(final TransactionExecutor txn, final String govId) {
          try {
              final String documentId = Person.getDocumentIdByGovId(txn, govId);
              final String query = "SELECT v FROM Vehicle AS v INNER JOIN VehicleRegistration AS r "
                      + "ON v.VIN = r.VIN WHERE r.Owners.PrimaryOwner.PersonId = ?";
  
              final Result result = txn.execute(query, Constants.MAPPER.writeValueAsIonValue(documentId));
              log.info("List of Vehicles for owner with GovId: {}...", govId);
              ScanTable.printDocuments(result);
          } catch (IOException ioe) {
              throw new IllegalStateException(ioe);
          }
      }
  
      public static void main(final String... args) {
          final Person person = SampleData.PEOPLE.get(0);
          ConnectToLedger.getDriver().execute(txn -> {
              findVehiclesForOwner(txn, person.getGovId());
          }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
      }
  }
  ```

------
**Nota**  
Innanzitutto, questo programma interroga la `Person` tabella del documento per ottenere il relativo campo `GovId LEWISR261LL` di metadati. `id`  
Quindi, utilizza questo documento `id` come chiave esterna per interrogare la `VehicleRegistration` tabella. `PrimaryOwner.PersonId` Inoltre si unisce `VehicleRegistration` alla `Vehicle` tabella sul `VIN` campo.

Per ulteriori informazioni sulla modifica dei documenti nelle tabelle del `vehicle-registration` libro mastro, consulta. [Fase 5: Modificare i documenti in un libro mastro](getting-started.java.step-5.md)

# Fase 5: Modificare i documenti in un libro mastro
<a name="getting-started.java.step-5"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Ora che hai dei dati su cui lavorare, puoi iniziare a modificare i documenti nel `vehicle-registration` registro di Amazon QLDB. In questa fase, i seguenti esempi di codice mostrano come eseguire istruzioni DML (Data Manipulation Language). Queste istruzioni aggiornano il proprietario principale di un veicolo e aggiungono un proprietario secondario a un altro veicolo.

**Per modificare i documenti**

1. Compila ed esegui il seguente programma (`TransferVehicleOwnership.java`) per aggiornare il proprietario principale del veicolo con il VIN `1N4AL11D75C109151` nel registro.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonReader;
   import com.amazon.ion.IonStruct;
   import com.amazon.ion.IonValue;
   import com.amazon.ion.system.IonReaderBuilder;
   
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.LinkedHashMap;
   import java.util.List;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.Owner;
   import software.amazon.qldb.tutorial.model.Person;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Find primary owner for a particular vehicle's VIN.
    * Transfer to another primary owner for a particular vehicle's VIN.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class TransferVehicleOwnership {
       public static final Logger log = LoggerFactory.getLogger(TransferVehicleOwnership.class);
   
       private TransferVehicleOwnership() { }
   
       /**
        * Query a driver's information using the given ID.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param documentId
        *              The unique ID of a document in the Person table.
        * @return a {@link Person} object.
        * @throws IllegalStateException if failed to convert parameter into {@link IonValue}.
        */
       public static Person findPersonFromDocumentId(final TransactionExecutor txn, final String documentId) {
           try {
               log.info("Finding person for documentId: {}...", documentId);
               final String query = "SELECT p.* FROM Person AS p BY pid WHERE pid = ?";
   
               Result result = txn.execute(query, Constants.MAPPER.writeValueAsIonValue(documentId));
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to find person with ID: " + documentId);
               }
   
               return Constants.MAPPER.readValue(result.iterator().next(), Person.class);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Find the primary owner for the given VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @return a {@link Person} object.
        * @throws IllegalStateException if failed to convert parameter into {@link IonValue}.
        */
       public static Person findPrimaryOwnerForVehicle(final TransactionExecutor txn, final String vin) {
           try {
               log.info("Finding primary owner for vehicle with Vin: {}...", vin);
               final String query = "SELECT Owners.PrimaryOwner.PersonId FROM VehicleRegistration AS v WHERE v.VIN = ?";
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(vin));
               Result result = txn.execute(query, parameters);
               final List<IonStruct> documents = ScanTable.toIonStructs(result);
               ScanTable.printDocuments(documents);
               if (documents.isEmpty()) {
                   throw new IllegalStateException("Unable to find registrations with VIN: " + vin);
               }
   
               final IonReader reader = IonReaderBuilder.standard().build(documents.get(0));
               final String personId = Constants.MAPPER.readValue(reader, LinkedHashMap.class).get("PersonId").toString();
               return findPersonFromDocumentId(txn, personId);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Update the primary owner for a vehicle registration with the given documentId.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @param documentId
        *              New PersonId for the primary owner.
        * @throws IllegalStateException if no vehicle registration was found using the given document ID and VIN, or if failed
        * to convert parameters into {@link IonValue}.
        */
       public static void updateVehicleRegistration(final TransactionExecutor txn, final String vin, final String documentId) {
           try {
               log.info("Updating primary owner for vehicle with Vin: {}...", vin);
               final String query = "UPDATE VehicleRegistration AS v SET v.Owners.PrimaryOwner = ? WHERE v.VIN = ?";
   
               final List<IonValue> parameters = new ArrayList<>();
               parameters.add(Constants.MAPPER.writeValueAsIonValue(new Owner(documentId)));
               parameters.add(Constants.MAPPER.writeValueAsIonValue(vin));
   
               Result result = txn.execute(query, parameters);
               ScanTable.printDocuments(result);
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to transfer vehicle, could not find registration.");
               } else {
                   log.info("Successfully transferred vehicle with VIN '{}' to new owner.", vin);
               }
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       public static void main(final String... args) {
           final String vin = SampleData.VEHICLES.get(0).getVin();
           final String primaryOwnerGovId = SampleData.PEOPLE.get(0).getGovId();
           final String newPrimaryOwnerGovId = SampleData.PEOPLE.get(1).getGovId();
   
           ConnectToLedger.getDriver().execute(txn -> {
               final Person primaryOwner = findPrimaryOwnerForVehicle(txn, vin);
               if (!primaryOwner.getGovId().equals(primaryOwnerGovId)) {
                   // Verify the primary owner.
                   throw new IllegalStateException("Incorrect primary owner identified for vehicle, unable to transfer.");
               }
   
               final String newOwner = Person.getDocumentIdByGovId(txn, newPrimaryOwnerGovId);
               updateVehicleRegistration(txn, vin, newOwner);
           });
           log.info("Successfully transferred vehicle ownership!");
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonReader;
   import com.amazon.ion.IonStruct;
   import com.amazon.ion.IonValue;
   import com.amazon.ion.system.IonReaderBuilder;
   
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.LinkedHashMap;
   import java.util.List;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.Owner;
   import software.amazon.qldb.tutorial.model.Person;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Find primary owner for a particular vehicle's VIN.
    * Transfer to another primary owner for a particular vehicle's VIN.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class TransferVehicleOwnership {
       public static final Logger log = LoggerFactory.getLogger(TransferVehicleOwnership.class);
   
       private TransferVehicleOwnership() { }
   
       /**
        * Query a driver's information using the given ID.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param documentId
        *              The unique ID of a document in the Person table.
        * @return a {@link Person} object.
        * @throws IllegalStateException if failed to convert parameter into {@link IonValue}.
        */
       public static Person findPersonFromDocumentId(final TransactionExecutor txn, final String documentId) {
           try {
               log.info("Finding person for documentId: {}...", documentId);
               final String query = "SELECT p.* FROM Person AS p BY pid WHERE pid = ?";
   
               Result result = txn.execute(query, Constants.MAPPER.writeValueAsIonValue(documentId));
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to find person with ID: " + documentId);
               }
   
               return Constants.MAPPER.readValue(result.iterator().next(), Person.class);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Find the primary owner for the given VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @return a {@link Person} object.
        * @throws IllegalStateException if failed to convert parameter into {@link IonValue}.
        */
       public static Person findPrimaryOwnerForVehicle(final TransactionExecutor txn, final String vin) {
           try {
               log.info("Finding primary owner for vehicle with Vin: {}...", vin);
               final String query = "SELECT Owners.PrimaryOwner.PersonId FROM VehicleRegistration AS v WHERE v.VIN = ?";
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(vin));
               Result result = txn.execute(query, parameters);
               final List<IonStruct> documents = ScanTable.toIonStructs(result);
               ScanTable.printDocuments(documents);
               if (documents.isEmpty()) {
                   throw new IllegalStateException("Unable to find registrations with VIN: " + vin);
               }
   
               final IonReader reader = IonReaderBuilder.standard().build(documents.get(0));
               final String personId = Constants.MAPPER.readValue(reader, LinkedHashMap.class).get("PersonId").toString();
               return findPersonFromDocumentId(txn, personId);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Update the primary owner for a vehicle registration with the given documentId.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @param documentId
        *              New PersonId for the primary owner.
        * @throws IllegalStateException if no vehicle registration was found using the given document ID and VIN, or if failed
        * to convert parameters into {@link IonValue}.
        */
       public static void updateVehicleRegistration(final TransactionExecutor txn, final String vin, final String documentId) {
           try {
               log.info("Updating primary owner for vehicle with Vin: {}...", vin);
               final String query = "UPDATE VehicleRegistration AS v SET v.Owners.PrimaryOwner = ? WHERE v.VIN = ?";
   
               final List<IonValue> parameters = new ArrayList<>();
               parameters.add(Constants.MAPPER.writeValueAsIonValue(new Owner(documentId)));
               parameters.add(Constants.MAPPER.writeValueAsIonValue(vin));
   
               Result result = txn.execute(query, parameters);
               ScanTable.printDocuments(result);
               if (result.isEmpty()) {
                   throw new IllegalStateException("Unable to transfer vehicle, could not find registration.");
               } else {
                   log.info("Successfully transferred vehicle with VIN '{}' to new owner.", vin);
               }
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       public static void main(final String... args) {
           final String vin = SampleData.VEHICLES.get(0).getVin();
           final String primaryOwnerGovId = SampleData.PEOPLE.get(0).getGovId();
           final String newPrimaryOwnerGovId = SampleData.PEOPLE.get(1).getGovId();
   
           ConnectToLedger.getDriver().execute(txn -> {
               final Person primaryOwner = findPrimaryOwnerForVehicle(txn, vin);
               if (!primaryOwner.getGovId().equals(primaryOwnerGovId)) {
                   // Verify the primary owner.
                   throw new IllegalStateException("Incorrect primary owner identified for vehicle, unable to transfer.");
               }
   
               final String newOwner = Person.getDocumentIdByGovId(txn, newPrimaryOwnerGovId);
               updateVehicleRegistration(txn, vin, newOwner);
           }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
           log.info("Successfully transferred vehicle ownership!");
       }
   }
   ```

------

1. Compila ed esegui il seguente programma (`AddSecondaryOwner.java`) per aggiungere un proprietario secondario al veicolo con VIN `KM8SRDHF6EU074761` nel registro.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import java.io.IOException;
   import java.util.Collections;
   import java.util.Iterator;
   import java.util.List;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import com.amazon.ion.IonValue;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.Owner;
   import software.amazon.qldb.tutorial.model.Owners;
   import software.amazon.qldb.tutorial.model.Person;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Finds and adds secondary owners for a vehicle.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class AddSecondaryOwner {
       public static final Logger log = LoggerFactory.getLogger(AddSecondaryOwner.class);
   
       private AddSecondaryOwner() { }
   
       /**
        * Check whether a secondary owner has already been registered for the given VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @param secondaryOwnerId
        *              The secondary owner to add.
        * @return {@code true} if the given secondary owner has already been registered, {@code false} otherwise.
        * @throws IllegalStateException if failed to convert VIN to an {@link IonValue}.
        */
       public static boolean isSecondaryOwnerForVehicle(final TransactionExecutor txn, final String vin,
                                                        final String secondaryOwnerId) {
           try {
               log.info("Finding secondary owners for vehicle with VIN: {}...", vin);
               final String query = "SELECT Owners.SecondaryOwners FROM VehicleRegistration AS v WHERE v.VIN = ?";
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(vin));
               final Result result = txn.execute(query, parameters);
               final Iterator<IonValue> itr = result.iterator();
               if (!itr.hasNext()) {
                   return false;
               }
   
               final Owners owners = Constants.MAPPER.readValue(itr.next(), Owners.class);
               if (null != owners.getSecondaryOwners()) {
                   for (Owner owner : owners.getSecondaryOwners()) {
                       if (secondaryOwnerId.equalsIgnoreCase(owner.getPersonId())) {
                           return true;
                       }
                   }
               }
   
               return false;
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Adds a secondary owner for the specified VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @param secondaryOwner
        *              The secondary owner to add.
        * @throws IllegalStateException if failed to convert parameter into an {@link IonValue}.
        */
       public static void addSecondaryOwnerForVin(final TransactionExecutor txn, final String vin,
                                                  final String secondaryOwner) {
           try {
               log.info("Inserting secondary owner for vehicle with VIN: {}...", vin);
               final String query = String.format("FROM VehicleRegistration AS v WHERE v.VIN = ?" +
                       "INSERT INTO v.Owners.SecondaryOwners VALUE ?");
               final IonValue newOwner = Constants.MAPPER.writeValueAsIonValue(new Owner(secondaryOwner));
               final IonValue vinAsIonValue = Constants.MAPPER.writeValueAsIonValue(vin);
               Result result = txn.execute(query, vinAsIonValue, newOwner);
               log.info("VehicleRegistration Document IDs which had secondary owners added: ");
               ScanTable.printDocuments(result);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       public static void main(final String... args) {
           final String vin = SampleData.VEHICLES.get(1).getVin();
           final String govId = SampleData.PEOPLE.get(0).getGovId();
   
           ConnectToLedger.getDriver().execute(txn -> {
               final String documentId = Person.getDocumentIdByGovId(txn, govId);
               if (isSecondaryOwnerForVehicle(txn, vin, documentId)) {
                   log.info("Person with ID {} has already been added as a secondary owner of this vehicle.", govId);
               } else {
                   addSecondaryOwnerForVin(txn, vin, documentId);
               }
           });
           log.info("Secondary owners successfully updated.");
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import java.io.IOException;
   import java.util.Collections;
   import java.util.Iterator;
   import java.util.List;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import com.amazon.ion.IonValue;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.Owner;
   import software.amazon.qldb.tutorial.model.Owners;
   import software.amazon.qldb.tutorial.model.Person;
   import software.amazon.qldb.tutorial.model.SampleData;
   
   /**
    * Finds and adds secondary owners for a vehicle.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class AddSecondaryOwner {
       public static final Logger log = LoggerFactory.getLogger(AddSecondaryOwner.class);
   
       private AddSecondaryOwner() { }
   
       /**
        * Check whether a secondary owner has already been registered for the given VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @param secondaryOwnerId
        *              The secondary owner to add.
        * @return {@code true} if the given secondary owner has already been registered, {@code false} otherwise.
        * @throws IllegalStateException if failed to convert VIN to an {@link IonValue}.
        */
       public static boolean isSecondaryOwnerForVehicle(final TransactionExecutor txn, final String vin,
                                                        final String secondaryOwnerId) {
           try {
               log.info("Finding secondary owners for vehicle with VIN: {}...", vin);
               final String query = "SELECT Owners.SecondaryOwners FROM VehicleRegistration AS v WHERE v.VIN = ?";
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(vin));
               final Result result = txn.execute(query, parameters);
               final Iterator<IonValue> itr = result.iterator();
               if (!itr.hasNext()) {
                   return false;
               }
   
               final Owners owners = Constants.MAPPER.readValue(itr.next(), Owners.class);
               if (null != owners.getSecondaryOwners()) {
                   for (Owner owner : owners.getSecondaryOwners()) {
                       if (secondaryOwnerId.equalsIgnoreCase(owner.getPersonId())) {
                           return true;
                       }
                   }
               }
   
               return false;
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Adds a secondary owner for the specified VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              Unique VIN for a vehicle.
        * @param secondaryOwner
        *              The secondary owner to add.
        * @throws IllegalStateException if failed to convert parameter into an {@link IonValue}.
        */
       public static void addSecondaryOwnerForVin(final TransactionExecutor txn, final String vin,
                                                  final String secondaryOwner) {
           try {
               log.info("Inserting secondary owner for vehicle with VIN: {}...", vin);
               final String query = String.format("FROM VehicleRegistration AS v WHERE v.VIN = '%s' " +
                       "INSERT INTO v.Owners.SecondaryOwners VALUE ?", vin);
               final IonValue newOwner = Constants.MAPPER.writeValueAsIonValue(new Owner(secondaryOwner));
               Result result = txn.execute(query, newOwner);
               log.info("VehicleRegistration Document IDs which had secondary owners added: ");
               ScanTable.printDocuments(result);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       public static void main(final String... args) {
           final String vin = SampleData.VEHICLES.get(1).getVin();
           final String govId = SampleData.PEOPLE.get(0).getGovId();
   
           ConnectToLedger.getDriver().execute(txn -> {
               final String documentId = Person.getDocumentIdByGovId(txn, govId);
               if (isSecondaryOwnerForVehicle(txn, vin, documentId)) {
                   log.info("Person with ID {} has already been added as a secondary owner of this vehicle.", govId);
               } else {
                   addSecondaryOwnerForVin(txn, vin, documentId);
               }
           }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
           log.info("Secondary owners successfully updated.");
       }
   }
   ```

------

Per esaminare queste modifiche nel `vehicle-registration` libro mastro, consulta. [Fase 6: Visualizzare la cronologia delle revisioni di un documento](getting-started.java.step-6.md)

# Fase 6: Visualizzare la cronologia delle revisioni di un documento
<a name="getting-started.java.step-6"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Dopo aver modificato i dati di immatricolazione di un veicolo nel passaggio precedente, puoi interrogare la cronologia di tutti i proprietari registrati e qualsiasi altro campo aggiornato. In questo passaggio, esegui una query sulla cronologia delle revisioni di un documento nella `VehicleRegistration` tabella del registro. `vehicle-registration`

**Per visualizzare la cronologia delle revisioni**

1. Esamina il seguente programma (`QueryHistory.java`).

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import java.io.IOException;
   import java.time.Instant;
   import java.time.temporal.ChronoUnit;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import com.amazon.ion.IonValue;
   
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   import software.amazon.qldb.tutorial.model.VehicleRegistration;
   
   /**
    * Query a table's history for a particular set of documents.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class QueryHistory {
       public static final Logger log = LoggerFactory.getLogger(QueryHistory.class);
       private static final int THREE_MONTHS = 90;
   
       private QueryHistory() { }
   
       /**
        * In this example, query the 'VehicleRegistration' history table to find all previous primary owners for a VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              VIN to find previous primary owners for.
        * @param query
        *              The query to find previous primary owners.
        * @throws IllegalStateException if failed to convert document ID to an {@link IonValue}.
        */
       public static void previousPrimaryOwners(final TransactionExecutor txn, final String vin, final String query) {
           try {
               final String docId = VehicleRegistration.getDocumentIdByVin(txn, vin);
   
               log.info("Querying the 'VehicleRegistration' table's history using VIN: {}...", vin);
               final Result result = txn.execute(query, Constants.MAPPER.writeValueAsIonValue(docId));
               ScanTable.printDocuments(result);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       public static void main(final String... args) {
           final String threeMonthsAgo = Instant.now().minus(THREE_MONTHS, ChronoUnit.DAYS).toString();
           final String query = String.format("SELECT data.Owners.PrimaryOwner, metadata.version "
                                              + "FROM history(VehicleRegistration, `%s`) "
                                              + "AS h WHERE h.metadata.id = ?", threeMonthsAgo);
           ConnectToLedger.getDriver().execute(txn -> {
               final String vin = SampleData.VEHICLES.get(0).getVin();
               previousPrimaryOwners(txn, vin, query);
           });
           log.info("Successfully queried history.");
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonValue;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.QldbSession;
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   import software.amazon.qldb.tutorial.model.VehicleRegistration;
   
   import java.io.IOException;
   import java.time.Instant;
   import java.time.temporal.ChronoUnit;
   import java.util.Collections;
   import java.util.List;
   
   /**
    * Query a table's history for a particular set of documents.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class QueryHistory {
       public static final Logger log = LoggerFactory.getLogger(QueryHistory.class);
       private static final int THREE_MONTHS = 90;
   
       private QueryHistory() { }
   
       /**
        * In this example, query the 'VehicleRegistration' history table to find all previous primary owners for a VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              VIN to find previous primary owners for.
        * @param query
        *              The query to find previous primary owners.
        * @throws IllegalStateException if failed to convert document ID to an {@link IonValue}.
        */
       public static void previousPrimaryOwners(final TransactionExecutor txn, final String vin, final String query) {
           try {
               final String docId = VehicleRegistration.getDocumentIdByVin(txn, vin);
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(docId));
               log.info("Querying the 'VehicleRegistration' table's history using VIN: {}...", vin);
               final Result result = txn.execute(query, parameters);
               ScanTable.printDocuments(result);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       public static void main(final String... args) {
           final String threeMonthsAgo = Instant.now().minus(THREE_MONTHS, ChronoUnit.DAYS).toString();
           final String query = String.format("SELECT data.Owners.PrimaryOwner, metadata.version "
                                              + "FROM history(VehicleRegistration, `%s`) "
                                              + "AS h WHERE h.metadata.id = ?", threeMonthsAgo);
           ConnectToLedger.getDriver().execute(txn -> {
               final String vin = SampleData.VEHICLES.get(0).getVin();
               previousPrimaryOwners(txn, vin, query);
           }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
           log.info("Successfully queried history.");
       }
   }
   ```

------
**Nota**  
È possibile visualizzare la cronologia delle revisioni di un documento interrogando la sintassi incorporata [Funzione di cronologia](working.history.md#working.history.function) nella seguente sintassi.  

     ```
     SELECT * FROM history( table_name [, `start-time` [, `end-time` ] ] ) AS h
     [ WHERE h.metadata.id = 'id' ]
     ```
L'*ora di inizio* e l'ora di *fine* sono entrambe opzionali. Sono valori letterali di Amazon Ion che possono essere indicati con backticks (). ``...`` Per ulteriori informazioni, consulta [Interrogazione di Ion con PartiQL in Amazon QLDB](ql-reference.query.md).
Come best practice, qualifica una query cronologica con un intervallo di date (ora di *inizio e ora di fine) e un* *ID del documento ()*. `metadata.id` [QLDB `SELECT` elabora le query nelle transazioni, che sono soggette a un limite di timeout delle transazioni.](limits.md#limits.fixed)  
La cronologia QLDB è indicizzata in base all'ID del documento e al momento non è possibile creare indici di cronologia aggiuntivi. Le interrogazioni cronologiche che includono l'ora di inizio e l'ora di fine ottengono il vantaggio della qualificazione per intervalli di date.

1. Compila ed esegui il `QueryHistory.java` programma per interrogare la cronologia delle revisioni del `VehicleRegistration` documento con VIN. `1N4AL11D75C109151`

Per verificare crittograficamente una revisione del documento nel registro, procedi a. `vehicle-registration` [Passaggio 7: Verificare un documento in un libro mastro](getting-started.java.step-7.md)

# Passaggio 7: Verificare un documento in un libro mastro
<a name="getting-started.java.step-7"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Con Amazon QLDB, puoi verificare in modo efficiente l'integrità di un documento nel diario del tuo libro mastro utilizzando l'hashing crittografico con SHA-256. Per ulteriori informazioni su come funzionano la verifica e l'hashing crittografico in QLDB, consulta. [Verifica dei dati in Amazon QLDB](verification.md)

In questo passaggio, verifichi una revisione del documento nella tabella del `VehicleRegistration` registro. `vehicle-registration` Innanzitutto, richiedi un digest, che viene restituito come file di output e funge da firma dell'intera cronologia delle modifiche del registro. Quindi, richiedi una bozza della revisione relativa a quel digest. Utilizzando questa prova, l'integrità della revisione viene verificata se tutti i controlli di convalida vengono superati.

**Per verificare la revisione di un documento**

1. Esamina i seguenti `.java` file, che rappresentano oggetti QLDB necessari per la verifica e le classi di utilità con metodi di supporto per i valori Ion e string.

   1. `BlockAddress.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import java.util.Objects;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import com.fasterxml.jackson.annotation.JsonCreator;
      import com.fasterxml.jackson.annotation.JsonProperty;
      
      /**
       * Represents the BlockAddress field of a QLDB document.
       */
      public final class BlockAddress {
      
          private static final Logger log = LoggerFactory.getLogger(BlockAddress.class);
      
          private final String strandId;
          private final long sequenceNo;
      
          @JsonCreator
          public BlockAddress(@JsonProperty("strandId") final String strandId,
                              @JsonProperty("sequenceNo") final long sequenceNo) {
              this.strandId = strandId;
              this.sequenceNo = sequenceNo;
          }
      
          public long getSequenceNo() {
              return sequenceNo;
          }
      
          public String getStrandId() {
              return strandId;
          }
      
          @Override
          public String toString() {
              return "BlockAddress{"
                      + "strandId='" + strandId + '\''
                      + ", sequenceNo=" + sequenceNo
                      + '}';
          }
      
          @Override
          public boolean equals(final Object o) {
              if (this == o) {
                  return true;
              }
              if (o == null || getClass() != o.getClass()) {
                  return false;
              }
              BlockAddress that = (BlockAddress) o;
              return sequenceNo == that.sequenceNo
                      && strandId.equals(that.strandId);
          }
      
          @Override
          public int hashCode() {
              // CHECKSTYLE:OFF - Disabling as we are generating a hashCode of multiple properties.
              return Objects.hash(strandId, sequenceNo);
              // CHECKSTYLE:ON
          }
      }
      ```

   1. `Proof.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import com.amazon.ion.IonReader;
      import com.amazon.ion.IonSystem;
      import com.amazon.ion.system.IonSystemBuilder;
      import com.amazonaws.services.qldb.model.GetRevisionRequest;
      import com.amazonaws.services.qldb.model.GetRevisionResult;
      
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * A Java representation of the {@link Proof} object.
       * Returned from the {@link com.amazonaws.services.qldb.AmazonQLDB#getRevision(GetRevisionRequest)} api.
       */
      public final class Proof {
          private static final IonSystem SYSTEM = IonSystemBuilder.standard().build();
      
          private List<byte[]> internalHashes;
      
          public Proof(final List<byte[]> internalHashes) {
              this.internalHashes = internalHashes;
          }
      
          public List<byte[]> getInternalHashes() {
              return internalHashes;
          }
      
          /**
           * Decodes a {@link Proof} from an ion text String. This ion text is returned in
           * a {@link GetRevisionResult#getProof()}
           *
           * @param ionText
           *              The ion text representing a {@link Proof} object.
           * @return {@link JournalBlock} parsed from the ion text.
           * @throws IllegalStateException if failed to parse the {@link Proof} object from the given ion text.
           */
          public static Proof fromBlob(final String ionText) {
              try {
                  IonReader reader = SYSTEM.newReader(ionText);
                  List<byte[]> list = new ArrayList<>();
                  reader.next();
                  reader.stepIn();
                  while (reader.next() != null) {
                      list.add(reader.newBytes());
                  }
                  return new Proof(list);
              } catch (Exception e) {
                  throw new IllegalStateException("Failed to parse a Proof from byte array");
              }
          }
      }
      ```

   1. `QldbIonUtils.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import com.amazon.ion.IonReader;
      import com.amazon.ion.IonValue;
      import com.amazon.ionhash.IonHashReader;
      import com.amazon.ionhash.IonHashReaderBuilder;
      import com.amazon.ionhash.MessageDigestIonHasherProvider;
      import software.amazon.qldb.tutorial.Constants;
      
      public class QldbIonUtils {
      
          private static MessageDigestIonHasherProvider ionHasherProvider = new MessageDigestIonHasherProvider("SHA-256");
      
          private QldbIonUtils() {}
      
          /**
           * Builds a hash value from the given {@link IonValue}.
           *
           * @param ionValue
           *              The {@link IonValue} to hash.
           * @return a byte array representing the hash value.
           */
          public static byte[] hashIonValue(final IonValue ionValue) {
              IonReader reader = Constants.SYSTEM.newReader(ionValue);
              IonHashReader hashReader = IonHashReaderBuilder.standard()
                      .withHasherProvider(ionHasherProvider)
                      .withReader(reader)
                      .build();
              while (hashReader.next() != null) {  }
              return hashReader.digest();
          }
      
      }
      ```

   1. `QldbStringUtils.java`

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial.qldb;
      
      import com.amazon.ion.IonWriter;
      import com.amazon.ion.system.IonReaderBuilder;
      import com.amazon.ion.system.IonTextWriterBuilder;
      import com.amazonaws.services.qldb.model.GetBlockResult;
      import com.amazonaws.services.qldb.model.GetDigestResult;
      import com.amazonaws.services.qldb.model.ValueHolder;
      
      import java.io.IOException;
      
      /**
       * Helper methods to pretty-print certain QLDB response types.
       */
      public class QldbStringUtils {
      
          private QldbStringUtils() {}
      
          /**
           * Returns the string representation of a given {@link ValueHolder}.
           * Adapted from the AWS SDK autogenerated {@code toString()} method, with sensitive values un-redacted.
           * Additionally, this method pretty-prints any IonText included in the {@link ValueHolder}.
           *
           * @param valueHolder the {@link ValueHolder} to convert to a String.
           * @return the String representation of the supplied {@link ValueHolder}.
           */
          public static String toUnredactedString(ValueHolder valueHolder) {
              StringBuilder sb = new StringBuilder();
              sb.append("{");
              if (valueHolder.getIonText() != null) {
      
                  sb.append("IonText: ");
                  IonWriter prettyWriter = IonTextWriterBuilder.pretty().build(sb);
                  try {
                      prettyWriter.writeValues(IonReaderBuilder.standard().build(valueHolder.getIonText()));
                  } catch (IOException ioe) {
                      sb.append("**Exception while printing this IonText**");
                  }
              }
      
              sb.append("}");
              return sb.toString();
          }
      
          /**
           * Returns the string representation of a given {@link GetBlockResult}.
           * Adapted from the AWS SDK autogenerated {@code toString()} method, with sensitive values un-redacted.
           *
           * @param getBlockResult the {@link GetBlockResult} to convert to a String.
           * @return the String representation of the supplied {@link GetBlockResult}.
           */
          public static String toUnredactedString(GetBlockResult getBlockResult) {
              StringBuilder sb = new StringBuilder();
              sb.append("{");
              if (getBlockResult.getBlock() != null) {
                  sb.append("Block: ").append(toUnredactedString(getBlockResult.getBlock())).append(",");
              }
      
              if (getBlockResult.getProof() != null) {
                  sb.append("Proof: ").append(toUnredactedString(getBlockResult.getProof()));
              }
      
              sb.append("}");
              return sb.toString();
          }
      
          /**
           * Returns the string representation of a given {@link GetDigestResult}.
           * Adapted from the AWS SDK autogenerated {@code toString()} method, with sensitive values un-redacted.
           *
           * @param getDigestResult the {@link GetDigestResult} to convert to a String.
           * @return the String representation of the supplied {@link GetDigestResult}.
           */
          public static String toUnredactedString(GetDigestResult getDigestResult) {
              StringBuilder sb = new StringBuilder();
              sb.append("{");
              if (getDigestResult.getDigest() != null) {
                  sb.append("Digest: ").append(getDigestResult.getDigest()).append(",");
              }
      
              if (getDigestResult.getDigestTipAddress() != null) {
                  sb.append("DigestTipAddress: ").append(toUnredactedString(getDigestResult.getDigestTipAddress()));
              }
      
              sb.append("}");
              return sb.toString();
          }
      }
      ```

   1. `Verifier.java`

------
#### [ 2.x ]

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial;
      
      import java.nio.ByteBuffer;
      import java.nio.charset.StandardCharsets;
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.util.ArrayList;
      import java.util.Arrays;
      import java.util.Comparator;
      import java.util.Iterator;
      import java.util.List;
      import java.util.concurrent.ThreadLocalRandom;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      import com.amazonaws.util.Base64;
      
      import software.amazon.qldb.tutorial.qldb.Proof;
      
      /**
       * Encapsulates the logic to verify the integrity of revisions or blocks in a QLDB ledger.
       *
       * The main entry point is {@link #verify(byte[], byte[], String)}.
       *
       * This code expects that you have AWS credentials setup per:
       * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
       */
      public final class Verifier {
          public static final Logger log = LoggerFactory.getLogger(Verifier.class);
          private static final int HASH_LENGTH = 32;
          private static final int UPPER_BOUND = 8;
      
          /**
           * Compares two hashes by their <em>signed</em> byte values in little-endian order.
           */
          private static Comparator<byte[]> hashComparator = (h1, h2) -> {
              if (h1.length != HASH_LENGTH || h2.length != HASH_LENGTH) {
                  throw new IllegalArgumentException("Invalid hash.");
              }
              for (int i = h1.length - 1; i >= 0; i--) {
                  int byteEqual = Byte.compare(h1[i], h2[i]);
                  if (byteEqual != 0) {
                      return byteEqual;
                  }
              }
      
              return 0;
          };
      
          private Verifier() { }
      
          /**
           * Verify the integrity of a document with respect to a QLDB ledger digest.
           *
           * The verification algorithm includes the following steps:
           *
           * 1. {@link #buildCandidateDigest(Proof, byte[])} build the candidate digest from the internal hashes
           * in the {@link Proof}.
           * 2. Check that the {@code candidateLedgerDigest} is equal to the {@code ledgerDigest}.
           *
           * @param documentHash
           *              The hash of the document to be verified.
           * @param digest
           *              The QLDB ledger digest. This digest should have been retrieved using
           *              {@link com.amazonaws.services.qldb.AmazonQLDB#getDigest}
           * @param proofBlob
           *              The ion encoded bytes representing the {@link Proof} associated with the supplied
           *              {@code digestTipAddress} and {@code address} retrieved using
           *              {@link com.amazonaws.services.qldb.AmazonQLDB#getRevision}.
           * @return {@code true} if the record is verified or {@code false} if it is not verified.
           */
          public static boolean verify(
                  final byte[] documentHash,
                  final byte[] digest,
                  final String proofBlob
          ) {
              Proof proof = Proof.fromBlob(proofBlob);
      
              byte[] candidateDigest = buildCandidateDigest(proof, documentHash);
      
              return Arrays.equals(digest, candidateDigest);
          }
      
          /**
           * Build the candidate digest representing the entire ledger from the internal hashes of the {@link Proof}.
           *
           * @param proof
           *              A Java representation of {@link Proof}
           *              returned from {@link com.amazonaws.services.qldb.AmazonQLDB#getRevision}.
           * @param leafHash
           *              Leaf hash to build the candidate digest with.
           * @return a byte array of the candidate digest.
           */
          private static byte[] buildCandidateDigest(final Proof proof, final byte[] leafHash) {
              return calculateRootHashFromInternalHashes(proof.getInternalHashes(), leafHash);
          }
      
          /**
           * Get a new instance of {@link MessageDigest} using the SHA-256 algorithm.
           *
           * @return an instance of {@link MessageDigest}.
           * @throws IllegalStateException if the algorithm is not available on the current JVM.
           */
          static MessageDigest newMessageDigest() {
              try {
                  return MessageDigest.getInstance("SHA-256");
              } catch (NoSuchAlgorithmException e) {
                  log.error("Failed to create SHA-256 MessageDigest", e);
                  throw new IllegalStateException("SHA-256 message digest is unavailable", e);
              }
          }
      
          /**
           * Takes two hashes, sorts them, concatenates them, and then returns the
           * hash of the concatenated array.
           *
           * @param h1
           *              Byte array containing one of the hashes to compare.
           * @param h2
           *              Byte array containing one of the hashes to compare.
           * @return the concatenated array of hashes.
           */
          public static byte[] dot(final byte[] h1, final byte[] h2) {
              if (h1.length == 0) {
                  return h2;
              }
              if (h2.length == 0) {
                  return h1;
              }
              byte[] concatenated = new byte[h1.length + h2.length];
              if (hashComparator.compare(h1, h2) < 0) {
                  System.arraycopy(h1, 0, concatenated, 0, h1.length);
                  System.arraycopy(h2, 0, concatenated, h1.length, h2.length);
              } else {
                  System.arraycopy(h2, 0, concatenated, 0, h2.length);
                  System.arraycopy(h1, 0, concatenated, h2.length, h1.length);
              }
              MessageDigest messageDigest = newMessageDigest();
              messageDigest.update(concatenated);
      
              return messageDigest.digest();
          }
      
          /**
           * Starting with the provided {@code leafHash} combined with the provided {@code internalHashes}
           * pairwise until only the root hash remains.
           *
           * @param internalHashes
           *              Internal hashes of Merkle tree.
           * @param leafHash
           *              Leaf hashes of Merkle tree.
           * @return the root hash.
           */
          private static byte[] calculateRootHashFromInternalHashes(final List<byte[]> internalHashes, final byte[] leafHash) {
              return internalHashes.stream().reduce(leafHash, Verifier::dot);
          }
      
          /**
           * Flip a single random bit in the given byte array. This method is used to demonstrate
           * QLDB's verification features.
           *
           * @param original
           *              The original byte array.
           * @return the altered byte array with a single random bit changed.
           */
          public static byte[] flipRandomBit(final byte[] original) {
              if (original.length == 0) {
                  throw new IllegalArgumentException("Array cannot be empty!");
              }
              int alteredPosition = ThreadLocalRandom.current().nextInt(original.length);
              int b = ThreadLocalRandom.current().nextInt(UPPER_BOUND);
              byte[] altered = new byte[original.length];
              System.arraycopy(original, 0, altered, 0, original.length);
              altered[alteredPosition] = (byte) (altered[alteredPosition] ^ (1 << b));
              return altered;
          }
      
          public static String toBase64(byte[] arr) {
              return new String(Base64.encode(arr), StandardCharsets.UTF_8);
          }
      
          /**
           * Convert a {@link ByteBuffer} into byte array.
           *
           * @param buffer
           *              The {@link ByteBuffer} to convert.
           * @return the converted byte array.
           */
          public static byte[] convertByteBufferToByteArray(final ByteBuffer buffer) {
              byte[] arr = new byte[buffer.remaining()];
              buffer.get(arr);
              return arr;
          }
      
          /**
           * Calculates the root hash from a list of hashes that represent the base of a Merkle tree.
           *
           * @param hashes
           *              The list of byte arrays representing hashes making up base of a Merkle tree.
           * @return a byte array that is the root hash of the given list of hashes.
           */
          public static byte[] calculateMerkleTreeRootHash(List<byte[]> hashes) {
              if (hashes.isEmpty()) {
                  return new byte[0];
              }
      
              List<byte[]> remaining = combineLeafHashes(hashes);
              while (remaining.size() > 1) {
                  remaining = combineLeafHashes(remaining);
              }
              return remaining.get(0);
          }
      
          private static List<byte[]> combineLeafHashes(List<byte[]> hashes) {
              List<byte[]> combinedHashes = new ArrayList<>();
              Iterator<byte[]> it = hashes.stream().iterator();
      
              while (it.hasNext()) {
                  byte[] left = it.next();
                  if (it.hasNext()) {
                      byte[] right = it.next();
                      byte[] combined = dot(left, right);
                      combinedHashes.add(combined);
                  } else {
                      combinedHashes.add(left);
                  }
              }
      
              return combinedHashes;
          }
      }
      ```

------
#### [ 1.x ]

      ```
      /*
       * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
       * SPDX-License-Identifier: MIT-0
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this
       * software and associated documentation files (the "Software"), to deal in the Software
       * without restriction, including without limitation the rights to use, copy, modify,
       * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
       * permit persons to whom the Software is furnished to do so.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      package software.amazon.qldb.tutorial;
      
      import com.amazonaws.util.Base64;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import software.amazon.qldb.tutorial.qldb.Proof;
      
      import java.nio.ByteBuffer;
      import java.nio.charset.StandardCharsets;
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.util.*;
      import java.util.concurrent.ThreadLocalRandom;
      
      /**
       * Encapsulates the logic to verify the integrity of revisions or blocks in a QLDB ledger.
       *
       * The main entry point is {@link #verify(byte[], byte[], String)}.
       *
       * This code expects that you have AWS credentials setup per:
       * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
       */
      public final class Verifier {
          public static final Logger log = LoggerFactory.getLogger(Verifier.class);
          private static final int HASH_LENGTH = 32;
          private static final int UPPER_BOUND = 8;
      
          /**
           * Compares two hashes by their <em>signed</em> byte values in little-endian order.
           */
          private static Comparator<byte[]> hashComparator = (h1, h2) -> {
              if (h1.length != HASH_LENGTH || h2.length != HASH_LENGTH) {
                  throw new IllegalArgumentException("Invalid hash.");
              }
              for (int i = h1.length - 1; i >= 0; i--) {
                  int byteEqual = Byte.compare(h1[i], h2[i]);
                  if (byteEqual != 0) {
                      return byteEqual;
                  }
              }
      
              return 0;
          };
      
          private Verifier() { }
      
          /**
           * Verify the integrity of a document with respect to a QLDB ledger digest.
           *
           * The verification algorithm includes the following steps:
           *
           * 1. {@link #buildCandidateDigest(Proof, byte[])} build the candidate digest from the internal hashes
           * in the {@link Proof}.
           * 2. Check that the {@code candidateLedgerDigest} is equal to the {@code ledgerDigest}.
           *
           * @param documentHash
           *              The hash of the document to be verified.
           * @param digest
           *              The QLDB ledger digest. This digest should have been retrieved using
           *              {@link com.amazonaws.services.qldb.AmazonQLDB#getDigest}
           * @param proofBlob
           *              The ion encoded bytes representing the {@link Proof} associated with the supplied
           *              {@code digestTipAddress} and {@code address} retrieved using
           *              {@link com.amazonaws.services.qldb.AmazonQLDB#getRevision}.
           * @return {@code true} if the record is verified or {@code false} if it is not verified.
           */
          public static boolean verify(
                  final byte[] documentHash,
                  final byte[] digest,
                  final String proofBlob
          ) {
              Proof proof = Proof.fromBlob(proofBlob);
      
              byte[] candidateDigest = buildCandidateDigest(proof, documentHash);
      
              return Arrays.equals(digest, candidateDigest);
          }
      
          /**
           * Build the candidate digest representing the entire ledger from the internal hashes of the {@link Proof}.
           *
           * @param proof
           *              A Java representation of {@link Proof}
           *              returned from {@link com.amazonaws.services.qldb.AmazonQLDB#getRevision}.
           * @param leafHash
           *              Leaf hash to build the candidate digest with.
           * @return a byte array of the candidate digest.
           */
          private static byte[] buildCandidateDigest(final Proof proof, final byte[] leafHash) {
              return calculateRootHashFromInternalHashes(proof.getInternalHashes(), leafHash);
          }
      
          /**
           * Get a new instance of {@link MessageDigest} using the SHA-256 algorithm.
           *
           * @return an instance of {@link MessageDigest}.
           * @throws IllegalStateException if the algorithm is not available on the current JVM.
           */
          static MessageDigest newMessageDigest() {
              try {
                  return MessageDigest.getInstance("SHA-256");
              } catch (NoSuchAlgorithmException e) {
                  log.error("Failed to create SHA-256 MessageDigest", e);
                  throw new IllegalStateException("SHA-256 message digest is unavailable", e);
              }
          }
      
          /**
           * Takes two hashes, sorts them, concatenates them, and then returns the
           * hash of the concatenated array.
           *
           * @param h1
           *              Byte array containing one of the hashes to compare.
           * @param h2
           *              Byte array containing one of the hashes to compare.
           * @return the concatenated array of hashes.
           */
          public static byte[] dot(final byte[] h1, final byte[] h2) {
              if (h1.length == 0) {
                  return h2;
              }
              if (h2.length == 0) {
                  return h1;
              }
              byte[] concatenated = new byte[h1.length + h2.length];
              if (hashComparator.compare(h1, h2) < 0) {
                  System.arraycopy(h1, 0, concatenated, 0, h1.length);
                  System.arraycopy(h2, 0, concatenated, h1.length, h2.length);
              } else {
                  System.arraycopy(h2, 0, concatenated, 0, h2.length);
                  System.arraycopy(h1, 0, concatenated, h2.length, h1.length);
              }
              MessageDigest messageDigest = newMessageDigest();
              messageDigest.update(concatenated);
      
              return messageDigest.digest();
          }
      
          /**
           * Starting with the provided {@code leafHash} combined with the provided {@code internalHashes}
           * pairwise until only the root hash remains.
           *
           * @param internalHashes
           *              Internal hashes of Merkle tree.
           * @param leafHash
           *              Leaf hashes of Merkle tree.
           * @return the root hash.
           */
          private static byte[] calculateRootHashFromInternalHashes(final List<byte[]> internalHashes, final byte[] leafHash) {
              return internalHashes.stream().reduce(leafHash, Verifier::dot);
          }
      
          /**
           * Flip a single random bit in the given byte array. This method is used to demonstrate
           * QLDB's verification features.
           *
           * @param original
           *              The original byte array.
           * @return the altered byte array with a single random bit changed.
           */
          public static byte[] flipRandomBit(final byte[] original) {
              if (original.length == 0) {
                  throw new IllegalArgumentException("Array cannot be empty!");
              }
              int alteredPosition = ThreadLocalRandom.current().nextInt(original.length);
              int b = ThreadLocalRandom.current().nextInt(UPPER_BOUND);
              byte[] altered = new byte[original.length];
              System.arraycopy(original, 0, altered, 0, original.length);
              altered[alteredPosition] = (byte) (altered[alteredPosition] ^ (1 << b));
              return altered;
          }
      
          public static String toBase64(byte[] arr) {
              return new String(Base64.encode(arr), StandardCharsets.UTF_8);
          }
      
          /**
           * Convert a {@link ByteBuffer} into byte array.
           *
           * @param buffer
           *              The {@link ByteBuffer} to convert.
           * @return the converted byte array.
           */
          public static byte[] convertByteBufferToByteArray(final ByteBuffer buffer) {
              byte[] arr = new byte[buffer.remaining()];
              buffer.get(arr);
              return arr;
          }
      
          /**
           * Calculates the root hash from a list of hashes that represent the base of a Merkle tree.
           *
           * @param hashes
           *              The list of byte arrays representing hashes making up base of a Merkle tree.
           * @return a byte array that is the root hash of the given list of hashes.
           */
          public static byte[] calculateMerkleTreeRootHash(List<byte[]> hashes) {
              if (hashes.isEmpty()) {
                  return new byte[0];
              }
      
              List<byte[]> remaining = combineLeafHashes(hashes);
              while (remaining.size() > 1) {
                  remaining = combineLeafHashes(remaining);
              }
              return remaining.get(0);
          }
      
          private static List<byte[]> combineLeafHashes(List<byte[]> hashes) {
              List<byte[]> combinedHashes = new ArrayList<>();
              Iterator<byte[]> it = hashes.stream().iterator();
      
              while (it.hasNext()) {
                  byte[] left = it.next();
                  if (it.hasNext()) {
                      byte[] right = it.next();
                      byte[] combined = dot(left, right);
                      combinedHashes.add(combined);
                  } else {
                      combinedHashes.add(left);
                  }
              }
      
              return combinedHashes;
          }
      }
      ```

------

1. Utilizzate due `.java` file (`GetDigest.java`e`GetRevision.java`) per eseguire le seguenti operazioni:
   + Richiedi un nuovo digest dal `vehicle-registration` registro.
   + Richiedi una bozza per ogni revisione di un documento dalla tabella. `VehicleRegistration`
   + Verifica le revisioni utilizzando il digest restituito e verifica ricalcolando il digest.

   Il `GetDigest.java` programma contiene il codice seguente.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.model.GetDigestRequest;
   import com.amazonaws.services.qldb.model.GetDigestResult;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.tutorial.qldb.QldbStringUtils;
   
   /**
    * This is an example for retrieving the digest of a particular ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class GetDigest {
       public static final Logger log = LoggerFactory.getLogger(GetDigest.class);
       public static AmazonQLDB client = CreateLedger.getClient();
   
       private GetDigest() { }
   
       /**
        * Calls {@link #getDigest(String)} for a ledger.
        *
        * @param args
        *              Arbitrary command-line arguments.
        * @throws Exception if failed to get a ledger digest.
        */
       public static void main(final String... args) throws Exception {
           try {
   
               getDigest(Constants.LEDGER_NAME);
   
           } catch (Exception e) {
               log.error("Unable to get a ledger digest!", e);
               throw e;
           }
       }
   
       /**
        * Get the digest for the specified ledger.
        *
        * @param ledgerName
        *              The ledger to get digest from.
        * @return {@link GetDigestResult}.
        */
       public static GetDigestResult getDigest(final String ledgerName) {
           log.info("Let's get the current digest of the ledger named {}.", ledgerName);
           GetDigestRequest request = new GetDigestRequest()
                   .withName(ledgerName);
           GetDigestResult result = client.getDigest(request);
           log.info("Success. LedgerDigest: {}.", QldbStringUtils.toUnredactedString(result));
           return result;
       }
   }
   ```
**Nota**  
Usa il `getDigest` metodo per richiedere un riassunto che copra la *punta* corrente del diario nel tuo libro mastro. Il tip of the journal si riferisce all'ultimo blocco eseguito nel momento in cui QLDB riceve la tua richiesta.

   Il `GetRevision.java` programma contiene il seguente codice.

------
#### [ 2.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonReader;
   import com.amazon.ion.IonStruct;
   import com.amazon.ion.IonSystem;
   import com.amazon.ion.IonValue;
   import com.amazon.ion.IonWriter;
   import com.amazon.ion.system.IonReaderBuilder;
   import com.amazon.ion.system.IonSystemBuilder;
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.model.GetDigestResult;
   import com.amazonaws.services.qldb.model.GetRevisionRequest;
   import com.amazonaws.services.qldb.model.GetRevisionResult;
   import com.amazonaws.services.qldb.model.ValueHolder;
   import java.io.ByteArrayOutputStream;
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.List;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.QldbDriver;
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   import software.amazon.qldb.tutorial.qldb.BlockAddress;
   import software.amazon.qldb.tutorial.qldb.QldbRevision;
   import software.amazon.qldb.tutorial.qldb.QldbStringUtils;
   
   /**
    * Verify the integrity of a document revision in a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class GetRevision {
       public static final Logger log = LoggerFactory.getLogger(GetRevision.class);
       public static AmazonQLDB client = CreateLedger.getClient();
       private static final IonSystem SYSTEM = IonSystemBuilder.standard().build();
   
       private GetRevision() { }
   
       public static void main(String... args) throws Exception {
   
           final String vin = SampleData.REGISTRATIONS.get(0).getVin();
   
   
           verifyRegistration(ConnectToLedger.getDriver(), Constants.LEDGER_NAME, vin);
       }
   
       /**
        * Verify each version of the registration for the given VIN.
        *
        * @param driver
        *              A QLDB driver.
        * @param ledgerName
        *              The ledger to get digest from.
        * @param vin
        *              VIN to query the revision history of a specific registration with.
        * @throws Exception if failed to verify digests.
        * @throws AssertionError if document revision verification failed.
        */
       public static void verifyRegistration(final QldbDriver driver, final String ledgerName, final String vin)
               throws Exception {
           log.info(String.format("Let's verify the registration with VIN=%s, in ledger=%s.", vin, ledgerName));
   
           try {
               log.info("First, let's get a digest.");
               GetDigestResult digestResult = GetDigest.getDigest(ledgerName);
   
               ValueHolder digestTipAddress = digestResult.getDigestTipAddress();
               byte[] digestBytes = Verifier.convertByteBufferToByteArray(digestResult.getDigest());
   
               log.info("Got a ledger digest. Digest end address={}, digest={}.",
                   QldbStringUtils.toUnredactedString(digestTipAddress),
                   Verifier.toBase64(digestBytes));
   
               log.info(String.format("Next, let's query the registration with VIN=%s. "
                       + "Then we can verify each version of the registration.", vin));
               List<IonStruct> documentsWithMetadataList = new ArrayList<>();
               driver.execute(txn -> {
                   documentsWithMetadataList.addAll(queryRegistrationsByVin(txn, vin));
               });
               log.info("Registrations queried successfully!");
   
               log.info(String.format("Found %s revisions of the registration with VIN=%s.",
                       documentsWithMetadataList.size(), vin));
   
               for (IonStruct ionStruct : documentsWithMetadataList) {
   
                   QldbRevision document = QldbRevision.fromIon(ionStruct);
                   log.info(String.format("Let's verify the document: %s", document));
   
                   log.info("Let's get a proof for the document.");
                   GetRevisionResult proofResult = getRevision(
                           ledgerName,
                           document.getMetadata().getId(),
                           digestTipAddress,
                           document.getBlockAddress()
                   );
   
                   final IonValue proof = Constants.MAPPER.writeValueAsIonValue(proofResult.getProof());
                   final IonReader reader = IonReaderBuilder.standard().build(proof);
                   reader.next();
                   ByteArrayOutputStream baos = new ByteArrayOutputStream();
                   IonWriter writer = SYSTEM.newBinaryWriter(baos);
                   writer.writeValue(reader);
                   writer.close();
                   baos.flush();
                   baos.close();
                   byte[] byteProof = baos.toByteArray();
   
                   log.info(String.format("Got back a proof: %s", Verifier.toBase64(byteProof)));
   
                   boolean verified = Verifier.verify(
                           document.getHash(),
                           digestBytes,
                           proofResult.getProof().getIonText()
                   );
   
                   if (!verified) {
                       throw new AssertionError("Document revision is not verified!");
                   } else {
                       log.info("Success! The document is verified");
                   }
   
                   byte[] alteredDigest = Verifier.flipRandomBit(digestBytes);
                   log.info(String.format("Flipping one bit in the digest and assert that the document is NOT verified. "
                           + "The altered digest is: %s", Verifier.toBase64(alteredDigest)));
                   verified = Verifier.verify(
                           document.getHash(),
                           alteredDigest,
                           proofResult.getProof().getIonText()
                   );
   
                   if (verified) {
                       throw new AssertionError("Expected document to not be verified against altered digest.");
                   } else {
                       log.info("Success! As expected flipping a bit in the digest causes verification to fail.");
                   }
   
                   byte[] alteredDocumentHash = Verifier.flipRandomBit(document.getHash());
                   log.info(String.format("Flipping one bit in the document's hash and assert that it is NOT verified. "
                           + "The altered document hash is: %s.", Verifier.toBase64(alteredDocumentHash)));
                   verified = Verifier.verify(
                           alteredDocumentHash,
                           digestBytes,
                           proofResult.getProof().getIonText()
                   );
   
                   if (verified) {
                       throw new AssertionError("Expected altered document hash to not be verified against digest.");
                   } else {
                       log.info("Success! As expected flipping a bit in the document hash causes verification to fail.");
                   }
               }
   
           } catch (Exception e) {
               log.error("Failed to verify digests.", e);
               throw e;
           }
   
           log.info(String.format("Finished verifying the registration with VIN=%s in ledger=%s.", vin, ledgerName));
       }
   
       /**
        * Get the revision of a particular document specified by the given document ID and block address.
        *
        * @param ledgerName
        *              Name of the ledger containing the document.
        * @param documentId
        *              Unique ID for the document to be verified, contained in the committed view of the document.
        * @param digestTipAddress
        *              The latest block location covered by the digest.
        * @param blockAddress
        *              The location of the block to request.
        * @return the requested revision.
        */
       public static GetRevisionResult getRevision(final String ledgerName, final String documentId,
                                                   final ValueHolder digestTipAddress, final BlockAddress blockAddress) {
           try {
               GetRevisionRequest request = new GetRevisionRequest()
                       .withName(ledgerName)
                       .withDigestTipAddress(digestTipAddress)
                       .withBlockAddress(new ValueHolder().withIonText(Constants.MAPPER.writeValueAsIonValue(blockAddress)
                               .toString()))
                       .withDocumentId(documentId);
               return client.getRevision(request);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Query the registration history for the given VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              The unique VIN to query.
        * @return a list of {@link IonStruct} representing the registration history.
        * @throws IllegalStateException if failed to convert parameters into {@link IonValue}
        */
       public static List<IonStruct> queryRegistrationsByVin(final TransactionExecutor txn, final String vin) {
           log.info(String.format("Let's query the 'VehicleRegistration' table for VIN: %s...", vin));
           log.info("Let's query the 'VehicleRegistration' table for VIN: {}...", vin);
           final String query = String.format("SELECT * FROM _ql_committed_%s WHERE data.VIN = ?",
                   Constants.VEHICLE_REGISTRATION_TABLE_NAME);
           try {
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(vin));
               final Result result = txn.execute(query, parameters);
               List<IonStruct> list = ScanTable.toIonStructs(result);
               log.info(String.format("Found %d document(s)!", list.size()));
               return list;
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   }
   ```

------
#### [ 1.x ]

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazon.ion.IonReader;
   import com.amazon.ion.IonStruct;
   import com.amazon.ion.IonValue;
   import com.amazon.ion.IonWriter;
   import com.amazon.ion.system.IonReaderBuilder;
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.model.GetDigestResult;
   import com.amazonaws.services.qldb.model.GetRevisionRequest;
   import com.amazonaws.services.qldb.model.GetRevisionResult;
   import com.amazonaws.services.qldb.model.ValueHolder;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.QldbSession;
   import software.amazon.qldb.Result;
   import software.amazon.qldb.TransactionExecutor;
   import software.amazon.qldb.tutorial.model.SampleData;
   import software.amazon.qldb.tutorial.qldb.BlockAddress;
   import software.amazon.qldb.tutorial.qldb.QldbRevision;
   import software.amazon.qldb.tutorial.qldb.QldbStringUtils;
   
   import java.io.ByteArrayOutputStream;
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collections;
   import java.util.List;
   
   /**
    * Verify the integrity of a document revision in a QLDB ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class GetRevision {
       public static final Logger log = LoggerFactory.getLogger(GetRevision.class);
       public static AmazonQLDB client = CreateLedger.getClient();
   
       private GetRevision() { }
   
       public static void main(String... args) throws Exception {
   
           final String vin = SampleData.REGISTRATIONS.get(0).getVin();
   
           try (QldbSession qldbSession = ConnectToLedger.createQldbSession()) {
               verifyRegistration(qldbSession, Constants.LEDGER_NAME, vin);
           }
       }
   
       /**
        * Verify each version of the registration for the given VIN.
        *
        * @param qldbSession
        *              A QLDB session.
        * @param ledgerName
        *              The ledger to get digest from.
        * @param vin
        *              VIN to query the revision history of a specific registration with.
        * @throws Exception if failed to verify digests.
        * @throws AssertionError if document revision verification failed.
        */
       public static void verifyRegistration(final QldbSession qldbSession, final String ledgerName, final String vin)
               throws Exception {
           log.info(String.format("Let's verify the registration with VIN=%s, in ledger=%s.", vin, ledgerName));
   
           try {
               log.info("First, let's get a digest.");
               GetDigestResult digestResult = GetDigest.getDigest(ledgerName);
   
               ValueHolder digestTipAddress = digestResult.getDigestTipAddress();
               byte[] digestBytes = Verifier.convertByteBufferToByteArray(digestResult.getDigest());
   
               log.info("Got a ledger digest. Digest end address={}, digest={}.",
                   QldbStringUtils.toUnredactedString(digestTipAddress),
                   Verifier.toBase64(digestBytes));
   
               log.info(String.format("Next, let's query the registration with VIN=%s. "
                       + "Then we can verify each version of the registration.", vin));
               List<IonStruct> documentsWithMetadataList = new ArrayList<>();
               qldbSession.execute(txn -> {
                   documentsWithMetadataList.addAll(queryRegistrationsByVin(txn, vin));
               }, (retryAttempt) -> log.info("Retrying due to OCC conflict..."));
               log.info("Registrations queried successfully!");
   
               log.info(String.format("Found %s revisions of the registration with VIN=%s.",
                       documentsWithMetadataList.size(), vin));
   
               for (IonStruct ionStruct : documentsWithMetadataList) {
   
                   QldbRevision document = QldbRevision.fromIon(ionStruct);
                   log.info(String.format("Let's verify the document: %s", document));
   
                   log.info("Let's get a proof for the document.");
                   GetRevisionResult proofResult = getRevision(
                           ledgerName,
                           document.getMetadata().getId(),
                           digestTipAddress,
                           document.getBlockAddress()
                   );
   
                   final IonValue proof = Constants.MAPPER.writeValueAsIonValue(proofResult.getProof());
                   final IonReader reader = IonReaderBuilder.standard().build(proof);
                   reader.next();
                   ByteArrayOutputStream baos = new ByteArrayOutputStream();
                   IonWriter writer = Constants.SYSTEM.newBinaryWriter(baos);
                   writer.writeValue(reader);
                   writer.close();
                   baos.flush();
                   baos.close();
                   byte[] byteProof = baos.toByteArray();
   
                   log.info(String.format("Got back a proof: %s", Verifier.toBase64(byteProof)));
   
                   boolean verified = Verifier.verify(
                           document.getHash(),
                           digestBytes,
                           proofResult.getProof().getIonText()
                   );
   
                   if (!verified) {
                       throw new AssertionError("Document revision is not verified!");
                   } else {
                       log.info("Success! The document is verified");
                   }
   
                   byte[] alteredDigest = Verifier.flipRandomBit(digestBytes);
                   log.info(String.format("Flipping one bit in the digest and assert that the document is NOT verified. "
                           + "The altered digest is: %s", Verifier.toBase64(alteredDigest)));
                   verified = Verifier.verify(
                           document.getHash(),
                           alteredDigest,
                           proofResult.getProof().getIonText()
                   );
   
                   if (verified) {
                       throw new AssertionError("Expected document to not be verified against altered digest.");
                   } else {
                       log.info("Success! As expected flipping a bit in the digest causes verification to fail.");
                   }
   
                   byte[] alteredDocumentHash = Verifier.flipRandomBit(document.getHash());
                   log.info(String.format("Flipping one bit in the document's hash and assert that it is NOT verified. "
                           + "The altered document hash is: %s.", Verifier.toBase64(alteredDocumentHash)));
                   verified = Verifier.verify(
                           alteredDocumentHash,
                           digestBytes,
                           proofResult.getProof().getIonText()
                   );
   
                   if (verified) {
                       throw new AssertionError("Expected altered document hash to not be verified against digest.");
                   } else {
                       log.info("Success! As expected flipping a bit in the document hash causes verification to fail.");
                   }
               }
   
           } catch (Exception e) {
               log.error("Failed to verify digests.", e);
               throw e;
           }
   
           log.info(String.format("Finished verifying the registration with VIN=%s in ledger=%s.", vin, ledgerName));
       }
   
       /**
        * Get the revision of a particular document specified by the given document ID and block address.
        *
        * @param ledgerName
        *              Name of the ledger containing the document.
        * @param documentId
        *              Unique ID for the document to be verified, contained in the committed view of the document.
        * @param digestTipAddress
        *              The latest block location covered by the digest.
        * @param blockAddress
        *              The location of the block to request.
        * @return the requested revision.
        */
       public static GetRevisionResult getRevision(final String ledgerName, final String documentId,
                                                   final ValueHolder digestTipAddress, final BlockAddress blockAddress) {
           try {
               GetRevisionRequest request = new GetRevisionRequest()
                       .withName(ledgerName)
                       .withDigestTipAddress(digestTipAddress)
                       .withBlockAddress(new ValueHolder().withIonText(Constants.MAPPER.writeValueAsIonValue(blockAddress)
                               .toString()))
                       .withDocumentId(documentId);
               return client.getRevision(request);
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   
       /**
        * Query the registration history for the given VIN.
        *
        * @param txn
        *              The {@link TransactionExecutor} for lambda execute.
        * @param vin
        *              The unique VIN to query.
        * @return a list of {@link IonStruct} representing the registration history.
        * @throws IllegalStateException if failed to convert parameters into {@link IonValue}
        */
       public static List<IonStruct> queryRegistrationsByVin(final TransactionExecutor txn, final String vin) {
           log.info(String.format("Let's query the 'VehicleRegistration' table for VIN: %s...", vin));
           log.info("Let's query the 'VehicleRegistration' table for VIN: {}...", vin);
           final String query = String.format("SELECT * FROM _ql_committed_%s WHERE data.VIN = ?",
                   Constants.VEHICLE_REGISTRATION_TABLE_NAME);
           try {
               final List<IonValue> parameters = Collections.singletonList(Constants.MAPPER.writeValueAsIonValue(vin));
               final Result result = txn.execute(query, parameters);
               List<IonStruct> list = ScanTable.toIonStructs(result);
               log.info(String.format("Found %d document(s)!", list.size()));
               return list;
           } catch (IOException ioe) {
               throw new IllegalStateException(ioe);
           }
       }
   }
   ```

------
**Nota**  
Dopo che il `getRevision` metodo ha restituito una bozza per la revisione del documento specificata, questo programma utilizza un'API lato client per verificare tale revisione. Per una panoramica dell'algoritmo utilizzato da questa API, consulta. [Utilizzo di una bozza per ricalcolare il riassunto](verification.results.md#verification.results.recalc)

1. Compila ed esegui il `GetRevision.java` programma per verificare crittograficamente il `VehicleRegistration` documento con VIN. `1N4AL11D75C109151`

Per esportare e convalidare i dati del giornale nel `vehicle-registration` libro mastro, procedi a. [Fase 8: Esportazione e convalida dei dati del diario in un libro mastro](getting-started.java.step-8.md)

# Fase 8: Esportazione e convalida dei dati del diario in un libro mastro
<a name="getting-started.java.step-8"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

In Amazon QLDB, puoi accedere ai contenuti del diario nel tuo registro per vari scopi, come la conservazione dei dati, l'analisi e il controllo. Per ulteriori informazioni, consulta [Esportazione dei dati del diario da Amazon QLDB](export-journal.md).

In questo passaggio, esporti i [blocchi di journal](journal-contents.md) dal `vehicle-registration` registro in un bucket Amazon S3. Quindi, usi i dati esportati per convalidare la catena di hash tra i blocchi di journal e i singoli componenti hash all'interno di ogni blocco.

L'entità principale AWS Identity and Access Management (IAM) che utilizzi deve disporre di autorizzazioni IAM sufficienti per creare un bucket Amazon S3 nel tuo. Account AWS Per informazioni, consulta [Policies and Permissions in Amazon S3 nella Amazon](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-policy-language-overview.html) S3 *User Guide*. È inoltre necessario disporre delle autorizzazioni per creare un ruolo IAM con una politica di autorizzazioni allegata che consenta a QLDB di scrivere oggetti nel bucket Amazon S3. *Per ulteriori informazioni, consulta [Autorizzazioni necessarie per accedere alle risorse IAM nella Guida per l'utente IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_permissions-required.html).*

**Per esportare e convalidare i dati del diario**

1. Esamina il seguente file (`JournalBlock.java`), che rappresenta un blocco di journal e il relativo contenuto di dati. Include un metodo denominato `verifyBlockHash()` che dimostra come calcolare ogni singolo componente di un block hash.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial.qldb;
   
   import com.fasterxml.jackson.annotation.JsonCreator;
   import com.fasterxml.jackson.annotation.JsonProperty;
   import com.fasterxml.jackson.databind.annotation.JsonSerialize;
   import com.fasterxml.jackson.dataformat.ion.IonTimestampSerializers;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   import software.amazon.qldb.tutorial.Constants;
   import software.amazon.qldb.tutorial.Verifier;
   
   import java.io.IOException;
   import java.nio.ByteBuffer;
   import java.util.Arrays;
   import java.util.Date;
   import java.util.HashSet;
   import java.util.List;
   import java.util.Set;
   import java.util.stream.Collectors;
   
   import static java.nio.ByteBuffer.wrap;
   
   /**
    * Represents a JournalBlock that was recorded after executing a transaction
    * in the ledger.
    */
   public final class JournalBlock {
       private static final Logger log = LoggerFactory.getLogger(JournalBlock.class);
   
       private BlockAddress blockAddress;
       private String transactionId;
       @JsonSerialize(using = IonTimestampSerializers.IonTimestampJavaDateSerializer.class)
       private Date blockTimestamp;
       private byte[] blockHash;
       private byte[] entriesHash;
       private byte[] previousBlockHash;
       private byte[][] entriesHashList;
       private TransactionInfo transactionInfo;
       private RedactionInfo redactionInfo;
       private List<QldbRevision> revisions;
   
       @JsonCreator
       public JournalBlock(@JsonProperty("blockAddress") final BlockAddress blockAddress,
                           @JsonProperty("transactionId") final String transactionId,
                           @JsonProperty("blockTimestamp") final Date blockTimestamp,
                           @JsonProperty("blockHash") final byte[] blockHash,
                           @JsonProperty("entriesHash") final byte[] entriesHash,
                           @JsonProperty("previousBlockHash") final byte[] previousBlockHash,
                           @JsonProperty("entriesHashList") final byte[][] entriesHashList,
                           @JsonProperty("transactionInfo") final TransactionInfo transactionInfo,
                           @JsonProperty("redactionInfo") final RedactionInfo redactionInfo,
                           @JsonProperty("revisions") final List<QldbRevision> revisions) {
           this.blockAddress = blockAddress;
           this.transactionId = transactionId;
           this.blockTimestamp = blockTimestamp;
           this.blockHash = blockHash;
           this.entriesHash = entriesHash;
           this.previousBlockHash = previousBlockHash;
           this.entriesHashList = entriesHashList;
           this.transactionInfo = transactionInfo;
           this.redactionInfo = redactionInfo;
           this.revisions = revisions;
       }
   
       public BlockAddress getBlockAddress() {
           return blockAddress;
       }
   
       public String getTransactionId() {
           return transactionId;
       }
   
       public Date getBlockTimestamp() {
           return blockTimestamp;
       }
   
       public byte[][] getEntriesHashList() {
           return entriesHashList;
       }
   
       public TransactionInfo getTransactionInfo() {
           return transactionInfo;
       }
   
       public RedactionInfo getRedactionInfo() {
           return redactionInfo;
       }
   
       public List<QldbRevision> getRevisions() {
           return revisions;
       }
   
       public byte[] getEntriesHash() {
           return entriesHash;
       }
   
       public byte[] getBlockHash() {
           return blockHash;
       }
   
       public byte[] getPreviousBlockHash() {
           return previousBlockHash;
       }
   
       @Override
       public String toString() {
           return "JournalBlock{"
                   + "blockAddress=" + blockAddress
                   + ", transactionId='" + transactionId + '\''
                   + ", blockTimestamp=" + blockTimestamp
                   + ", blockHash=" + Arrays.toString(blockHash)
                   + ", entriesHash=" + Arrays.toString(entriesHash)
                   + ", previousBlockHash=" + Arrays.toString(previousBlockHash)
                   + ", entriesHashList=" + Arrays.toString(entriesHashList)
                   + ", transactionInfo=" + transactionInfo
                   + ", redactionInfo=" + redactionInfo
                   + ", revisions=" + revisions
                   + '}';
       }
   
       @Override
       public boolean equals(final Object o) {
           if (this == o) {
               return true;
           }
           if (!(o instanceof JournalBlock)) {
               return false;
           }
   
           final JournalBlock that = (JournalBlock) o;
   
           if (!getBlockAddress().equals(that.getBlockAddress())) {
               return false;
           }
           if (!getTransactionId().equals(that.getTransactionId())) {
               return false;
           }
           if (!getBlockTimestamp().equals(that.getBlockTimestamp())) {
               return false;
           }
           if (!Arrays.equals(getBlockHash(), that.getBlockHash())) {
               return false;
           }
           if (!Arrays.equals(getEntriesHash(), that.getEntriesHash())) {
               return false;
           }
           if (!Arrays.equals(getPreviousBlockHash(), that.getPreviousBlockHash())) {
               return false;
           }
           if (!Arrays.deepEquals(getEntriesHashList(), that.getEntriesHashList())) {
               return false;
           }
           if (!getTransactionInfo().equals(that.getTransactionInfo())) {
               return false;
           }
           if (getRedactionInfo() != null ? !getRedactionInfo().equals(that.getRedactionInfo()) : that.getRedactionInfo() != null) {
               return false;
           }
           return getRevisions() != null ? getRevisions().equals(that.getRevisions()) : that.getRevisions() == null;
       }
   
       @Override
       public int hashCode() {
           int result = getBlockAddress().hashCode();
           result = 31 * result + getTransactionId().hashCode();
           result = 31 * result + getBlockTimestamp().hashCode();
           result = 31 * result + Arrays.hashCode(getBlockHash());
           result = 31 * result + Arrays.hashCode(getEntriesHash());
           result = 31 * result + Arrays.hashCode(getPreviousBlockHash());
           result = 31 * result + Arrays.deepHashCode(getEntriesHashList());
           result = 31 * result + getTransactionInfo().hashCode();
           result = 31 * result + (getRedactionInfo() != null ? getRedactionInfo().hashCode() : 0);
           result = 31 * result + (getRevisions() != null ? getRevisions().hashCode() : 0);
           return result;
       }
   
       /**
        * This method validates that the hashes of the components of a journal block make up the block
        * hash that is provided with the block itself.
        *
        * The components that contribute to the hash of the journal block consist of the following:
        *   - user transaction information (contained in [transactionInfo])
        *   - user redaction information (contained in [redactionInfo])
        *   - user revisions (contained in [revisions])
        *   - hashes of internal-only system metadata (contained in [revisions] and in [entriesHashList])
        *   - the previous block hash
        *
        * If any of the computed hashes of user information cannot be validated or any of the system
        * hashes do not result in the correct computed values, this method will throw an IllegalArgumentException.
        *
        * Internal-only system metadata is represented by its hash, and can be present in the form of certain
        * items in the [revisions] list that only contain a hash and no user data, as well as some hashes
        * in [entriesHashList].
        *
        * To validate that the hashes of the user data are valid components of the [blockHash], this method
        * performs the following steps:
        *
        * 1. Compute the hash of the [transactionInfo] and validate that it is included in the [entriesHashList].
        * 2. Compute the hash of the [redactionInfo], if present, and validate that it is included in the [entriesHashList].
        * 3. Validate the hash of each user revision was correctly computed and matches the hash published
        * with that revision.
        * 4. Compute the hash of the [revisions] by treating the revision hashes as the leaf nodes of a Merkle tree
        * and calculating the root hash of that tree. Then validate that hash is included in the [entriesHashList].
        * 5. Compute the hash of the [entriesHashList] by treating the hashes as the leaf nodes of a Merkle tree
        * and calculating the root hash of that tree. Then validate that hash matches [entriesHash].
        * 6. Finally, compute the block hash by computing the hash resulting from concatenating the [entriesHash]
        * and previous block hash, and validate that the result matches the [blockHash] provided by QLDB with the block.
        *
        * This method is called by ValidateQldbHashChain::verify for each journal block to validate its
        * contents before verifying that the hash chain between consecutive blocks is correct.
        */
       public void verifyBlockHash() {
           Set<ByteBuffer> entriesHashSet = new HashSet<>();
           Arrays.stream(entriesHashList).forEach(hash -> entriesHashSet.add(wrap(hash).asReadOnlyBuffer()));
   
           byte[] computedTransactionInfoHash = computeTransactionInfoHash();
           if (!entriesHashSet.contains(wrap(computedTransactionInfoHash).asReadOnlyBuffer())) {
               throw new IllegalArgumentException(
                       "Block transactionInfo hash is not contained in the QLDB block entries hash list.");
           }
   
           if (redactionInfo != null) {
               byte[] computedRedactionInfoHash = computeRedactionInfoHash();
               if (!entriesHashSet.contains(wrap(computedRedactionInfoHash).asReadOnlyBuffer())) {
                   throw new IllegalArgumentException(
                           "Block redactionInfo hash is not contained in the QLDB block entries hash list.");
               }
           }
   
           if (revisions != null) {
               revisions.forEach(QldbRevision::verifyRevisionHash);
               byte[] computedRevisionsHash = computeRevisionsHash();
               if (!entriesHashSet.contains(wrap(computedRevisionsHash).asReadOnlyBuffer())) {
                   throw new IllegalArgumentException(
                           "Block revisions list hash is not contained in the QLDB block entries hash list.");
               }
           }
   
           byte[] computedEntriesHash = computeEntriesHash();
           if (!Arrays.equals(computedEntriesHash, entriesHash)) {
               throw new IllegalArgumentException("Computed entries hash does not match entries hash provided in the block.");
           }
   
           byte[] computedBlockHash = Verifier.dot(computedEntriesHash, previousBlockHash);
           if (!Arrays.equals(computedBlockHash, blockHash)) {
               throw new IllegalArgumentException("Computed block hash does not match block hash provided in the block.");
           }
       }
   
       private byte[] computeTransactionInfoHash() {
           try {
               return QldbIonUtils.hashIonValue(Constants.MAPPER.writeValueAsIonValue(transactionInfo));
           } catch (IOException e) {
               throw new IllegalArgumentException("Could not compute transactionInfo hash to verify block hash.", e);
           }
       }
   
       private byte[] computeRedactionInfoHash() {
           try {
               return QldbIonUtils.hashIonValue(Constants.MAPPER.writeValueAsIonValue(redactionInfo));
           } catch (IOException e) {
               throw new IllegalArgumentException("Could not compute redactionInfo hash to verify block hash.", e);
           }
       }
   
       private byte[] computeRevisionsHash() {
           return Verifier.calculateMerkleTreeRootHash(revisions.stream().map(QldbRevision::getHash).collect(Collectors.toList()));
       }
   
       private byte[] computeEntriesHash() {
           return Verifier.calculateMerkleTreeRootHash(Arrays.asList(entriesHashList));
       }
   }
   ```

1. Compila ed esegui il seguente programma (`ValidateQldbHashChain.java`) per eseguire i seguenti passaggi:

   1. Esporta i blocchi del journal dal `vehicle-registration` registro in un bucket Amazon S3 **qldb-tutorial-journal-export-*111122223333*** denominato (sostituiscilo con Account AWS il tuo numero).

   1. Convalida i singoli componenti hash all'interno di ogni blocco chiamando. `verifyBlockHash()`

   1. Convalida la catena hash tra i blocchi di journal.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.services.qldb.model.ExportJournalToS3Result;
   import com.amazonaws.services.qldb.model.S3EncryptionConfiguration;
   import com.amazonaws.services.qldb.model.S3ObjectEncryptionType;
   import com.amazonaws.services.s3.AmazonS3ClientBuilder;
   
   import java.time.Instant;
   import java.util.Arrays;
   import java.util.List;
   
   import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
   import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest;
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   import software.amazon.qldb.tutorial.qldb.JournalBlock;
   
   /**
    * Validate the hash chain of a QLDB ledger by stepping through its S3 export.
    *
    * This code accepts an exportId as an argument, if exportId is passed the code
    * will use that or request QLDB to generate a new export to perform QLDB hash
    * chain validation.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class ValidateQldbHashChain {
       public static final Logger log = LoggerFactory.getLogger(ValidateQldbHashChain.class);
       private static final int TIME_SKEW = 20;
   
       private ValidateQldbHashChain() { }
   
       /**
        * Export journal contents to a S3 bucket.
        *
        * @return the ExportId of the journal export.
        * @throws InterruptedException if the thread is interrupted while waiting for export to complete.
        */
       private static String createExport() throws InterruptedException {
           String accountId = AWSSecurityTokenServiceClientBuilder.defaultClient()
               .getCallerIdentity(new GetCallerIdentityRequest()).getAccount();
           String bucketName = Constants.JOURNAL_EXPORT_S3_BUCKET_NAME_PREFIX + "-" + accountId;
           String prefix = Constants.LEDGER_NAME + "-" + Instant.now().getEpochSecond() + "/";
   
           S3EncryptionConfiguration encryptionConfiguration = new S3EncryptionConfiguration()
                   .withObjectEncryptionType(S3ObjectEncryptionType.SSE_S3);
           ExportJournalToS3Result exportJournalToS3Result = 
               ExportJournal.createJournalExportAndAwaitCompletion(Constants.LEDGER_NAME, 
                       bucketName, prefix, null, encryptionConfiguration, ExportJournal.DEFAULT_EXPORT_TIMEOUT_MS);
   
           return exportJournalToS3Result.getExportId();
       }
   
       /**
        * Validates that the chain hash on the {@link JournalBlock} is valid.
        *
        * @param journalBlocks
        *              {@link JournalBlock} containing hashes to validate.
        * @throws IllegalStateException if previous block hash does not match.
        */
       public static void verify(final List<JournalBlock> journalBlocks) {
           if (journalBlocks.size() == 0) {
               return;
           }
   
           journalBlocks.stream().reduce(null, (previousJournalBlock, journalBlock) -> {
               journalBlock.verifyBlockHash();
               if (previousJournalBlock == null) { return journalBlock; }
               if (!Arrays.equals(previousJournalBlock.getBlockHash(), journalBlock.getPreviousBlockHash())) {
                   throw new IllegalStateException("Previous block hash doesn't match.");
               }
               byte[] blockHash = Verifier.dot(journalBlock.getEntriesHash(), previousJournalBlock.getBlockHash());
               if (!Arrays.equals(blockHash, journalBlock.getBlockHash())) {
                   throw new IllegalStateException("Block hash doesn't match entriesHash dot previousBlockHash, the chain is "
                           + "broken.");
               }
               return journalBlock;
           });
       }
   
       public static void main(final String... args) throws InterruptedException {
           try {
               String exportId;
               if (args.length == 1) {
                   exportId = args[0];
                   log.info("Validating QLDB hash chain for exportId: " + exportId);
               } else {
                   log.info("Requesting QLDB to create an export.");
                   exportId = createExport();
               }
               List<JournalBlock> journalBlocks =
                   JournalS3ExportReader.readExport(DescribeJournalExport.describeExport(Constants.LEDGER_NAME,
                       exportId), AmazonS3ClientBuilder.defaultClient());
               verify(journalBlocks);
           } catch (Exception e) {
               log.error("Unable to perform hash chain verification.", e);
               throw e;
           }
       }
   
   }
   ```

Se non hai più bisogno di usare il `vehicle-registration` libro mastro, procedi con. [Passaggio 9 (opzionale): Pulisci le risorse](getting-started.java.step-9.md)

# Passaggio 9 (opzionale): Pulisci le risorse
<a name="getting-started.java.step-9"></a>

**Importante**  
Avviso di fine del supporto: i clienti esistenti potranno utilizzare Amazon QLDB fino alla fine del supporto, il 31/07/2025. Per ulteriori dettagli, consulta [Migrare un registro Amazon QLDB su Amazon Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/).

Puoi `vehicle-registration` continuare a utilizzare il registro. Tuttavia, se non è più necessario, è necessario eliminarlo.

**Per eliminare il libro mastro**

1. Compila ed esegui il seguente programma (`DeleteLedger.java`) per eliminare il `vehicle-registration` registro e tutto il suo contenuto.

   ```
   /*
    * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    * SPDX-License-Identifier: MIT-0
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy of this
    * software and associated documentation files (the "Software"), to deal in the Software
    * without restriction, including without limitation the rights to use, copy, modify,
    * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
    * permit persons to whom the Software is furnished to do so.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
    * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
   
   package software.amazon.qldb.tutorial;
   
   import com.amazonaws.services.qldb.AmazonQLDB;
   import com.amazonaws.services.qldb.model.DeleteLedgerRequest;
   import com.amazonaws.services.qldb.model.DeleteLedgerResult;
   import com.amazonaws.services.qldb.model.ResourceNotFoundException;
   import com.amazonaws.services.qldb.model.UpdateLedgerRequest;
   import com.amazonaws.services.qldb.model.UpdateLedgerResult;
   
   import org.slf4j.Logger;
   import org.slf4j.LoggerFactory;
   
   /**
    * Delete a ledger.
    *
    * This code expects that you have AWS credentials setup per:
    * http://docs.aws.amazon.com/java-sdk/latest/developer-guide/setup-credentials.html
    */
   public final class DeleteLedger {
       public static final Logger log = LoggerFactory.getLogger(DeleteLedger.class);
       public static final Long LEDGER_DELETION_POLL_PERIOD_MS = 20_000L;
       public static AmazonQLDB client = CreateLedger.getClient();
   
       private DeleteLedger() { }
   
       public static void main(String... args) throws Exception {
           try {
               setDeletionProtection(Constants.LEDGER_NAME, false);
   
               delete(Constants.LEDGER_NAME);
   
               waitForDeleted(Constants.LEDGER_NAME);
   
           } catch (Exception e) {
               log.error("Unable to delete the ledger.", e);
               throw e;
           }
       }
   
       /**
        * Send a request to the QLDB database to delete the specified ledger.
        *
        * @param ledgerName
        *              Name of the ledger to be deleted.
        * @return DeleteLedgerResult.
        */
       public static DeleteLedgerResult delete(final String ledgerName) {
           log.info("Attempting to delete the ledger with name: {}...", ledgerName);
           DeleteLedgerRequest request = new DeleteLedgerRequest().withName(ledgerName);
           DeleteLedgerResult result = client.deleteLedger(request);
           log.info("Success.");
           return result;
       }
   
       /**
        * Wait for the ledger to be deleted.
        *
        * @param ledgerName
        *              Name of the ledger being deleted.
        * @throws InterruptedException if thread is being interrupted.
        */
       public static void waitForDeleted(final String ledgerName) throws InterruptedException {
           log.info("Waiting for the ledger to be deleted...");
           while (true) {
               try {
                   DescribeLedger.describe(ledgerName);
                   log.info("The ledger is still being deleted. Please wait...");
                   Thread.sleep(LEDGER_DELETION_POLL_PERIOD_MS);
               } catch (ResourceNotFoundException ex) {
                   log.info("Success. The ledger is deleted.");
                   break;
               }
           }
       }
       
       public static UpdateLedgerResult setDeletionProtection(String ledgerName, boolean deletionProtection) {
           log.info("Let's set deletionProtection to {} for the ledger with name {}", deletionProtection, ledgerName);
           UpdateLedgerRequest request = new UpdateLedgerRequest()
                   .withName(ledgerName)
                   .withDeletionProtection(deletionProtection);
   
           UpdateLedgerResult result = client.updateLedger(request);
           log.info("Success. Ledger updated: {}", result);
           return result;
       }
   }
   ```
**Nota**  
Se la protezione da eliminazione è abilitata per il registro, devi prima disabilitarla prima di poter eliminare il registro utilizzando l'API QLDB.

1. Se hai esportato i dati del journal nel [passaggio precedente](getting-started.java.step-8.md) e non ne hai più bisogno, usa la console Amazon S3 per eliminare il tuo bucket S3.

   Apri la console Amazon S3 all'indirizzo. [https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/)