Skip to content

8. [TD]: Il livello [metier]

Parole chiave: architettura multistrato, Spring, iniezione di dipendenze.

8.1. Support

 

La cartella [support / chap-08] contiene il progetto Eclipse di questo capitolo.

8.2. Configurazione Maven

  

Il progetto [elections-metier-dao-jdbc] si baserà sul progetto [elections-dao-jdbc-01]. Installeremo il file JAR di quest'ultimo progetto nel repository Maven locale:

 

Una volta fatto ciò, la configurazione Maven del progetto Eclipse [elections-metier-dao-jdbc] è la seguente:

  

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-metier-dao-jdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- DAO -->
        <dependency>
            <groupId>istia.st.elections</groupId>
            <artifactId>elections-dao-jdbc-01</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- plugin -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>config.AppConfig</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
            <!-- per l'installazione dell'artifact del progetto nel repository Maven locale -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>
</project>
  • righe 21-25: la dipendenza dal file JAR del progetto [elections-jdbc-01]. Queste righe vengono copiate direttamente dal file [pom.xml] del progetto che si desidera importare:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-dao-jdbc-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
...
  • righe 26-37: le dipendenze necessarie per i test. Sebbene siano presenti nel file [pom.xml] del progetto [elections-jdbc-01], siamo costretti a reinserirle poiché il loro attributo [<scope>test</scope>] fa sì che non siano state incluse nel jar inserito nel repository Maven locale;

8.3. Configurazione Spring

  

package elections.metier.config;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

@Import({ elections.dao.config.AppConfig.class })
@EnableCaching
@ComponentScan(basePackages = { "elections.metier.service" })
public class MetierConfig {
}
  • riga 7: si importano tutti i bean definiti nel livello [DAO];
  • riga 8: si attiva la cache. Non si ridefinisce il bean [CacheManager], poiché è già definito nel livello [DAO];
  • riga 9: il livello [métier] definisce nuovi bean nel pacchetto [elections.metier.service];

8.4. L'interfaccia [IElectionsMetier]

  

Il livello [metier] avrà l'interfaccia descritta al paragrafo 4.2. La riportiamo di seguito:


public interface IElectionsMetier {

    public ListeElectorale[] getListesElectorales();

    public int getNbSiegesAPourvoir();

    public double getSeuilElectoral();

    public void recordResultats(ListeElectorale[] listesElectorales);

    public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales);

}

8.5. La classe di implementazione [ElectionsMetier]

  

Questa classe implementa l’interfaccia [IElectionsMetier]. L’implementazione proposta avrà la seguente struttura:


package elections.metier.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import elections.dao.entities.ListeElectorale;
import elections.dao.service.IElectionsDao;

@Component
public class ElectionsMetier implements IElectionsMetier {

    // il punto di accesso al livello [dao] istanziato da [Spring]
    @SuppressWarnings("unused")
    @Autowired
    private IElectionsDao electionsDao;

    // calcolo dei seggi ottenuti
  @Override
    public ListeElectorale[] calculerSieges(ListeElectorale[] listesElectorales) {
        throw new RuntimeException("[calculerSieges] not yet implemented");
    }

    // liste in competizione
  @Override
    public ListeElectorale[] getListesElectorales() {
        throw new RuntimeException("[getListesElectorales] not yet implemented");
    }

    // salvataggio dei risultati
  @Override
    public void recordResultats(ListeElectorale[] listesElectorales) {
        throw new RuntimeException("[recordResultats] not yet implemented");
    }

    // numero di seggi da assegnare
    @Override
    public int getNbSiegesAPourvoir() {
        throw new RuntimeException("[getNbSiegesAPourvoir] not yet implemented");
    }

    // soglia elettorale
    @Override
    public double getSeuilElectoral() {
        throw new RuntimeException("[getSeuilElectoral] not yet implemented");
    }

}
  • riga 10: la classe [ElectionsMetier] è un componente Spring;
  • riga 11: la classe [ElectionsMetier] implementa l'interfaccia [IElectionsMetier];
  • righe 15-16: iniezione Spring di un riferimento al livello [DAO];
  • righe 37 e 44: il numero di seggi da assegnare e la soglia elettorale vengono memorizzati nella cache;

Compito da svolgere: scrivere la classe [ElectionsMetier]. Ci si avvarrà dei commenti, ove presenti. Non si cercherà di gestire (try / catch) le eccezioni di tipo [ElectionsException] che vengono segnalate dal livello [DAO]. Le lasceremo propagarsi fino al livello [UI]. Poiché la classe [ElectionsException] è un tipo di eccezione non controllata, non è obbligatorio gestirla tramite un (try / catch).


8.6. La classe di test

  

La classe di test JUnit avrà la seguente struttura:


package tests;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import dao.config.AppConfig;
import dao.entities.ElectionsException;
import metier.service.IElectionsMetier;

@SpringApplicationConfiguration(classes = MetierConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {

    // livello [métier]
    @Autowired
    static private IElectionsMetier electionsMetier;

    /**
     * vérification 1 : méthode de calcul des sièges on fixe en dur les listes
     */
    @Test
    public void calculSieges1() {
        // si crea la tabella delle 7 liste candidate (nome, voti)

        // si calcolano i seggi di ciascuna lista

        // si verificano i risultati (seggi, voti, si eliminano)

        // temporaneo
        throw new RuntimeException("[calculSieges1] not yet implemented");
    }

    /**
     * vérification 2 : méthode de calcul des sièges on demande les listes à la
     * couche [metier] puis on fixe en dur les voix
     */
    @Test
    public void calculSieges2() {
        // si salva nella banca dati la tabella delle 7 liste candidate

        // si fissano in modo definitivo i voti

        // si calcolano i seggi ottenuti da ciascuna delle liste

        // si verificano i risultati (seggi, voti, si eliminano)

        // temporaneo
        throw new RuntimeException("[calculSieges2] not yet implemented");
    }

    /**
     * vérification 3 méthode de calcul des sièges on provoque une exception
     */
    @Test(expected = ElectionsException.class)
    // scrivere un test che provochi un'eccezione di tipo [ElectionsException]
    public void calculSieges3() {
        // si crea un array di 25 liste candidate con 1 voto ciascuna
        // le 25 liste avranno lo stesso numero di voti (4%)

        // calcolo dei seggi - normalmente si dovrebbe ottenere un ElectionsException
        // con una soglia elettorale del 5%

        // provvisorio
        throw new RuntimeException("[calculSieges3] not yet implemented");
    }

    /**
     * enregistrement des résultats de l'élection
     */
    @Test
    public void ecritureResultatsElections() {
        // si crea la tabella delle 7 liste candidate

        // si fissano in modo definitivo i voti

        // si calcolano i seggi ottenuti da ciascuna delle liste

        // si registrano i risultati nel database

        // si rileggono le liste presenti nel database

        // si verificano i risultati (seggi, voti, si eliminano)

        // temporaneo
        throw new RuntimeException("[ecritureResultatsElections] not yet implemented");
    }
}

Compito da svolgere: scrivere i quattro metodi di test avvalendosi dei commenti. Si ricordi che quando questi metodi vengono eseguiti, il campo [electionsMetier] della riga 19 è già stato inizializzato. Verificare che il test JUnit superi il controllo.


8.7. Creazione dell'archivio del livello [metier]

Come già fatto per il livello [DAO], inseriamo l’archivio del progetto [elections-metier-dao-jdbc] nel repository Maven locale:

 

Nota: questa operazione potrebbe non andare a buon fine se il vostro progetto Eclipse è associato a un JRE (Java Runtime Environment) anziché a un JDK (Java Development Kit). Per verificarlo, procedere come indicato al paragrafo 3.1. Se si scopre di avere un JRE anziché un JDK, associare il progetto a un JDK come indicato in questo paragrafo.

8.8. Conclusion

Ricordiamo l’architettura generale dell’applicazione [Elections] che stiamo realizzando:

Abbiamo realizzato i livelli [metier] e [dao]. Ora realizzeremo il livello [ui]. Proporremo due implementazioni per questo livello:

  • un'implementazione "da console"
  • un’implementazione con interfaccia grafica