Salta el contingut
 

Exercici: Proves d'una arquitectura d'un banc

Joan Puigcerver Ibáñez

j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Proves d'una arquitectura d'un banc

ud8.exercises.bank

Objectius

L'objectiu principal d'aquest exercici és posar en pràctica la creació de proves unitàries i d'integració utilitzant objectes simulats amb la llibreria Mockito i bases de dades incrustades H2 en una aplicació amb arquitectura per capes.

Enunciat

Se'ns ha demanat crear una aplicació bancària per gestionar els comptes bancaris dels clients. La nostra tasca consistirà en provar la funcionalitat de la implementació de les diferents capes mitjançant objectes simulats utilitzant Mockito.

Les proves que heu de fer són les següents:

  • Proves unitàries de la implementció de la capa de servei, utilitzant objectes simulats amb Mockito per la capa de repositori.
  • Proves unitàries de la implementció de la capa de repositori, utilitzant objectes simulats amb Mockito per la capa de DAO.
  • Proves unitàries de la implementció de la capa de DAO, utilitzant una base de dades incrustada H2.
  • Proves d'integració de la implementció de la capa de servei fins a la capa de DAO, utilitzant una base de dades incrustada H2.

Codi Font

ud8
├── common
│   ├── exception
│   │   └── ResourceNotFoundException.java
│   └── utils
│       └── AppPropertiesReader.java
├── exercises
│   └── bank
│       ├── domain
│       │   ├── entity
│       │   │   └── BankAccount.java
│       │   └── service
│       │       ├── BankAccountService.java
│       │       ├── impl
│       │       │   └── BankAccountServiceImpl.java
│       │       └── NotificationService.java
│       └── persistance
│           ├── dao
│           │   ├── BankAccountDao.java
│           │   └── impl
│           │       └── BankAccountDaoJdbc.java
│           ├── repository
│           │   ├── BankAccountRepository.java
│           │   └── impl
│           │       └── BankAccountRepositoryImpl.java
│           └── rowmapper
│               └── BankAccountRowMapper.java
└── persistance
    ├── database
    │   ├── DatabaseConnection.java
    │   └── ScriptRunner.java
    └── rowmapper
        └── RowMapper.java

Entitats

ud8.exercises.bank.domain.entity

BankAccount.java
package ud8.exercises.bank.domain.entity;

import java.util.Objects;

public class BankAccount {
    public final static int ACCOUNT_NUMBER_LENGTH = 2;

    private final String iban;
    private double balance;

    public BankAccount(String iban) {
        this(iban, 0);
    }

    public BankAccount(String iban, double balance) {
        this.iban = iban;
        this.balance = balance;
    }

    public String getIban() {
        return iban;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public int getAccountNumber() {
        return Integer.parseInt(iban.substring(2));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof BankAccount that)) return false;
        return Double.compare(balance, that.balance) == 0 && Objects.equals(iban, that.iban);
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "iban='" + iban + '\'' +
                ", balance=" + balance +
                '}';
    }
}

Serveis

ud8.exercises.bank.domain.service

Interfícies
BankAccountService.java
package ud8.exercises.bank.domain.service;

import ud8.common.exception.ResourceNotFoundException;
import ud8.exercises.bank.domain.entity.BankAccount;

public interface BankAccountService {
    BankAccount findByIBAN(String iban) throws ResourceNotFoundException;
    BankAccount create();
    boolean update(BankAccount bank);
    boolean delete(String iban);

    boolean deposit(BankAccount account, double amount);
    boolean withdraw(BankAccount account, double amount);
    boolean transfer(BankAccount from, BankAccount to, double amount);
}
NotificationService.java
package ud8.exercises.bank.domain.service;

import ud8.exercises.bank.domain.entity.BankAccount;

public interface NotificationService {
    void sendNotification(BankAccount account, String message);
}
Implementació
BankAccountServiceImpl.java
package ud8.exercises.bank.domain.service.impl;

import ud8.common.exception.ResourceNotFoundException;
import ud8.exercises.bank.domain.entity.BankAccount;
import ud8.exercises.bank.domain.service.BankAccountService;
import ud8.exercises.bank.domain.service.NotificationService;
import ud8.exercises.bank.persistance.repository.BankAccountRepository;

public class BankAccountServiceImpl implements BankAccountService {
    private final BankAccountRepository repository;
    private final NotificationService notificationService;

    public BankAccountServiceImpl(BankAccountRepository repository, NotificationService notificationService) {
        this.repository = repository;
        this.notificationService = notificationService;
    }

    @Override
    public BankAccount findByIBAN(String iban) throws ResourceNotFoundException {
        BankAccount bank = repository.findByIBAN(iban);
        if (bank == null)
            throw new ResourceNotFoundException("Bank account not found");
        return bank;
    }

    @Override
    public BankAccount create() {
        String newIBAN = generateIBAN();
        BankAccount account = new BankAccount(newIBAN);
        repository.save(account);
        notificationService.sendNotification(account, "Your new bank account has been created!");
        return account;
    }

    public String generateIBAN() {
        BankAccount latest = repository.latest();
        int accountNumber = latest == null ? 1 : latest.getAccountNumber() + 1;
        return String.format("ES%0" + BankAccount.ACCOUNT_NUMBER_LENGTH + "d", accountNumber);
    }

    @Override
    public boolean update(BankAccount bank) {
        if (!repository.existsByIBAN(bank.getIban())) {
            return false;
        }

        repository.save(bank);
        return true;
    }

    @Override
    public boolean delete(String iban) {
        if (!repository.existsByIBAN(iban)) {
            return false;
        }

        repository.delete(iban);
        return true;
    }

    @Override
    public boolean deposit(BankAccount account, double amount) {
        if (amount <= 0) {
            return false;
        }
        account.setBalance(account.getBalance() + amount);

        repository.save(account);
        return true;
    }

    @Override
    public boolean withdraw(BankAccount account, double amount) {
        if (amount <= 0 || account.getBalance() < amount) {
            return false;
        }
        account.setBalance(account.getBalance() - amount);

        repository.save(account);
        return true;
    }

    @Override
    public boolean transfer(BankAccount from, BankAccount to, double amount) {
        if (amount <= 0 || from.getBalance() < amount) {
            return false;
        }
        from.setBalance(from.getBalance() - amount);
        to.setBalance(to.getBalance() + amount);

        repository.save(from);
        repository.save(to);

        notificationService.sendNotification(from, "Transfer of " + amount + " to " + to.getIban());
        notificationService.sendNotification(to, "Transfer of " + amount + " from " + from.getIban());
        return true;
    }
}
NotificationServiceImpl.java
package ud8.exercises.bank.domain.service.impl;

import ud8.exercises.bank.domain.entity.BankAccount;
import ud8.exercises.bank.domain.service.NotificationService;

public class NotificationServiceImpl implements NotificationService {
    @Override
    public void sendNotification(BankAccount account, String message) {
        System.out.printf("%s: %s%n", account.getIban(), message);
    }
}

Repositoris

ud8.exercises.bank.persistance.repository

Interfícies
BankAccountRepository.java
package ud8.exercises.bank.persistance.repository;

import ud8.exercises.bank.domain.entity.BankAccount;

public interface BankAccountRepository {
    BankAccount findByIBAN(String iban);
    boolean existsByIBAN(String iban);
    BankAccount latest();
    void save(BankAccount bank);
    void delete(String iban);
}
Implementació
BankAccountRepositoryImpl.java
package ud8.exercises.bank.persistance.repository.impl;

import ud8.exercises.bank.domain.entity.BankAccount;
import ud8.exercises.bank.persistance.dao.BankAccountDao;
import ud8.exercises.bank.persistance.repository.BankAccountRepository;

public class BankAccountRepositoryImpl implements BankAccountRepository {
    private final BankAccountDao dao;

    public BankAccountRepositoryImpl(BankAccountDao dao) {
        this.dao = dao;
    }

    @Override
    public BankAccount findByIBAN(String iban) {
        return dao.findByIBAN(iban);
    }

    @Override
    public boolean existsByIBAN(String iban) {
        return dao.findByIBAN(iban) != null;
    }

    @Override
    public BankAccount latest() {
        return dao.latest();
    }

    @Override
    public void save(BankAccount bank) {
        if (dao.findByIBAN(bank.getIban()) == null)
            dao.insert(bank);
        else
            dao.update(bank);
    }

    @Override
    public void delete(String iban) {
        dao.delete(iban);
    }
}

DAO

ud8.exercises.bank.persistance.dao

Interfícies
BankAccountDao.java
package ud8.exercises.bank.persistance.dao;

import ud8.exercises.bank.domain.entity.BankAccount;

public interface BankAccountDao {
    BankAccount findByIBAN(String iban);
    BankAccount latest();
    void insert(BankAccount bank);
    void update(BankAccount bank);
    void delete(String iban);
}
Implementació
BankAccountDaoJdbc.java
package ud8.exercises.bank.persistance.dao.impl;

import ud8.exercises.bank.domain.entity.BankAccount;
import ud8.exercises.bank.persistance.dao.BankAccountDao;
import ud8.exercises.bank.persistance.rowmapper.BankAccountRowMapper;
import ud8.persistance.database.DatabaseConnection;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class BankAccountDaoJdbc implements BankAccountDao {
    private final DatabaseConnection connection;
    private final BankAccountRowMapper bankAccountRowMapper;

    public BankAccountDaoJdbc() {
        this.connection = DatabaseConnection.getInstance();
        this.bankAccountRowMapper = new BankAccountRowMapper();
    }

    @Override
    public BankAccount findByIBAN(String iban) {
        String sql = "SELECT * FROM bank_account WHERE iban = ?";
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            preparedStatement.setString(1, iban);
            ResultSet rs = preparedStatement.executeQuery();
            if (!rs.next())
                return null;

            return bankAccountRowMapper.mapItem(rs);
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public BankAccount latest() {
        String sql = "SELECT iban, balance FROM bank_account ORDER BY iban DESC LIMIT 1";
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            ResultSet rs = preparedStatement.executeQuery();
            if (!rs.next())
                return null;

            return bankAccountRowMapper.mapItem(rs);
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void insert(BankAccount bank) {
        String sql = "INSERT INTO bank_account (iban, balance) VALUES (?, ?)";
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            preparedStatement.setString(1, bank.getIban());
            preparedStatement.setDouble(2, bank.getBalance());
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void update(BankAccount bank) {
        String sql = "UPDATE bank_account SET balance = ? WHERE iban = ?";
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            preparedStatement.setDouble(1, bank.getBalance());
            preparedStatement.setString(2, bank.getIban());
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void delete(String iban) {
        String sql = "DELETE FROM bank_account WHERE iban = ?";
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            preparedStatement.setString(1, iban);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}

Base de dades

ud8.persistance.database

Nota

Aquestes classes són comunes als exemples i exercicis d'aquesta unitat.

DatabaseConnection.java
package ud8.persistance.database;

import lombok.extern.log4j.Log4j2;
import ud8.common.utils.AppPropertiesReader;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Log4j2
public class DatabaseConnection {

    // Singleton pattern
    private static DatabaseConnection instance = null;
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }

    private final String dbUrl;
    private final String dbUser;
    private final String dbPassword;
    private final Connection connection;

    private DatabaseConnection () {
        dbUrl = AppPropertiesReader.getProperty("app.datasource.url");
        dbUser = AppPropertiesReader.getProperty("app.datasource.username");
        dbPassword = AppPropertiesReader.getProperty("app.datasource.password");

        log.debug("Establint la connexió amb la base de dades...");
        try {
            connection = DriverManager.getConnection(
                    dbUrl,
                    dbUser,
                    dbPassword
            );
            log.debug("Connexió establerta amb èxit amb els paràmetres:");
            log.debug(this.getParameters());
        } catch (SQLException e) {
            log.error(e.getMessage());
            throw new RuntimeException("Connection parameters :\n\n" + getParameters() + "\nOriginal exception message: " + e.getMessage());
        }
    }

    private String getParameters (){
        return String.format("url: %s\nUser: %s\nPassword: %s\n",
                dbUrl,
                dbUser,
                dbPassword
        );
    }

    @SuppressWarnings("SqlSourceToSinkFlow")
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }

    public void setAutoCommit(boolean autoCommit) throws SQLException {
        connection.setAutoCommit(autoCommit);
    }

    public void rollback() throws SQLException {
        connection.rollback();
    }

    public void executeScript(String scriptPath) {
        try {
            ScriptRunner scriptRunner = new ScriptRunner(connection, false, false);

            InputStream scriptStream = getClass().getClassLoader().getResourceAsStream(scriptPath);
            if (scriptStream == null)
                throw new RuntimeException("Script not found: " + scriptPath);

            scriptRunner.runScript(new InputStreamReader(scriptStream));
        } catch (IOException | SQLException e) {
            throw new RuntimeException(String.format("Error executing script %s:\n    %s\n", scriptPath, e.getMessage()));
        }
    }
}
ScriptRunner.java
package ud8.persistance.database;

/*
 * Added additional null checks when closing the ResultSet and Statements.
 *
 * Thanks to pihug12 and Grzegorz Oledzki at stackoverflow.com
 * http://stackoverflow.com/questions/5332149/jdbc-scriptrunner-java-lang-nullpointerexception?tab=active#tab-top
 */
/*
 * Modified: Use logWriter in print(Object), JavaDoc comments, correct Typo.
 */
/*
 * Modified by Pantelis Sopasakis <chvng@mail.ntua.gr> to take care of DELIMITER statements. This way you
 * can execute scripts that contain some TRIGGER creation code. New version using REGEXPs! Latest
 * modification: Cater for a NullPointerException while parsing. Date: Feb 16, 2011, 11:48 EET
 */
/*
 * Slightly modified version of the com.ibatis.common.jdbc.ScriptRunner class from the iBATIS Apache
 * project. Only removed dependency on Resource class and a constructor
 */
/*
 * Copyright 2004 Clinton Begin Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Tool to run database scripts. This version of the script can be found at
 * https://gist.github.com/gists/831762/
 */
public class ScriptRunner {

    private static final String DEFAULT_DELIMITER = ";";
    private static final String DELIMITER_LINE_REGEX = "(?i)DELIMITER.+";
    private static final String DELIMITER_LINE_SPLIT_REGEX = "(?i)DELIMITER";

    private final Connection connection;
    private final boolean stopOnError;
    private final boolean autoCommit;
    private PrintWriter logWriter = new PrintWriter(System.out);
    private PrintWriter errorLogWriter = new PrintWriter(System.err);
    private String delimiter = DEFAULT_DELIMITER;
    private boolean fullLineDelimiter = false;

    /**
     * Default constructor.
     *
     * @param connection
     * @param autoCommit
     * @param stopOnError
     */
    public ScriptRunner(Connection connection, boolean autoCommit, boolean stopOnError) {
        this.connection = connection;
        this.autoCommit = autoCommit;
        this.stopOnError = stopOnError;
    }

    /**
     * @param delimiter
     * @param fullLineDelimiter
     */
    public void setDelimiter(String delimiter, boolean fullLineDelimiter) {
        this.delimiter = delimiter;
        this.fullLineDelimiter = fullLineDelimiter;
    }

    /**
     * Setter for logWriter property.
     *
     * @param logWriter
     *        - the new value of the logWriter property
     */
    public void setLogWriter(PrintWriter logWriter) {
        this.logWriter = logWriter;
    }

    /**
     * Setter for errorLogWriter property.
     *
     * @param errorLogWriter
     *        - the new value of the errorLogWriter property
     */
    public void setErrorLogWriter(PrintWriter errorLogWriter) {
        this.errorLogWriter = errorLogWriter;
    }

    /**
     * Runs an SQL script (read in using the Reader parameter).
     *
     * @param reader
     *        - the source of the script
     * @throws SQLException
     *         if any SQL errors occur
     * @throws IOException
     *         if there is an error reading from the Reader
     */
    public void runScript(Reader reader) throws IOException, SQLException {
        try {
            boolean originalAutoCommit = connection.getAutoCommit();
            try {
                if (originalAutoCommit != autoCommit) {
                    connection.setAutoCommit(autoCommit);
                }
                runScript(connection, reader);
            } finally {
                connection.setAutoCommit(originalAutoCommit);
            }
        } catch (IOException e) {
            throw e;
        } catch (SQLException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException("Error running script.  Cause: " + e, e);
        }
    }

    /**
     * Runs an SQL script (read in using the Reader parameter) using the connection passed in.
     *
     * @param conn
     *        - the connection to use for the script
     * @param reader
     *        - the source of the script
     * @throws SQLException
     *         if any SQL errors occur
     * @throws IOException
     *         if there is an error reading from the Reader
     */
    private void runScript(Connection conn, Reader reader) throws IOException, SQLException {
        StringBuffer command = null;
        try {
            LineNumberReader lineReader = new LineNumberReader(reader);
            String line = null;
            while ((line = lineReader.readLine()) != null) {
                if (command == null) {
                    command = new StringBuffer();
                }
                String trimmedLine = line.trim();
                if (trimmedLine.startsWith("--")) {
                    println(trimmedLine);
                } else if (trimmedLine.length() < 1 || trimmedLine.startsWith("//")) {
                    // Do nothing
                } else if (trimmedLine.length() < 1 || trimmedLine.startsWith("--")) {
                    // Do nothing
                } else if (!fullLineDelimiter && trimmedLine.endsWith(getDelimiter())
                        || fullLineDelimiter && trimmedLine.equals(getDelimiter())) {

                    Pattern pattern = Pattern.compile(DELIMITER_LINE_REGEX);
                    Matcher matcher = pattern.matcher(trimmedLine);
                    if (matcher.matches()) {
                        setDelimiter(trimmedLine.split(DELIMITER_LINE_SPLIT_REGEX)[1].trim(),
                                fullLineDelimiter);
                        line = lineReader.readLine();
                        if (line == null) {
                            break;
                        }
                        trimmedLine = line.trim();
                    }

                    command.append(line.substring(0, line.lastIndexOf(getDelimiter())));
                    command.append(" ");
                    Statement statement = conn.createStatement();

                    println(command);

                    boolean hasResults = false;
                    if (stopOnError) {
                        hasResults = statement.execute(command.toString());
                    } else {
                        try {
                            statement.execute(command.toString());
                        } catch (SQLException e) {
                            e.fillInStackTrace();
                            printlnError("Error executing: " + command);
                            printlnError(e);
                        }
                    }

                    if (autoCommit && !conn.getAutoCommit()) {
                        conn.commit();
                    }

                    ResultSet rs = statement.getResultSet();
                    if (hasResults && rs != null) {
                        ResultSetMetaData md = rs.getMetaData();
                        int cols = md.getColumnCount();
                        for (int i = 0; i < cols; i++) {
                            String name = md.getColumnLabel(i);
                            print(name + "\t");
                        }
                        println("");
                        while (rs.next()) {
                            for (int i = 1; i <= cols; i++) {
                                String value = rs.getString(i);
                                print(value + "\t");
                            }
                            println("");
                        }
                    }

                    command = null;
                    try {
                        if (rs != null) {
                            rs.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        if (statement != null) {
                            statement.close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        // Ignore to workaround a bug in Jakarta DBCP
                    }
                } else {
                    Pattern pattern = Pattern.compile(DELIMITER_LINE_REGEX);
                    Matcher matcher = pattern.matcher(trimmedLine);
                    if (matcher.matches()) {
                        setDelimiter(trimmedLine.split(DELIMITER_LINE_SPLIT_REGEX)[1].trim(),
                                fullLineDelimiter);
                        line = lineReader.readLine();
                        if (line == null) {
                            break;
                        }
                        trimmedLine = line.trim();
                    }
                    command.append(line);
                    command.append(" ");
                }
            }
            if (!autoCommit) {
                conn.commit();
            }
        } catch (SQLException e) {
            e.fillInStackTrace();
            printlnError("Error executing: " + command);
            printlnError(e);
            throw e;
        } catch (IOException e) {
            e.fillInStackTrace();
            printlnError("Error executing: " + command);
            printlnError(e);
            throw e;
        } finally {
            conn.rollback();
            flush();
        }
    }

    private String getDelimiter() {
        return delimiter;
    }

    private void print(Object o) {
        if (logWriter != null) {
            logWriter.print(o);
        }
    }

    private void println(Object o) {
        if (logWriter != null) {
            logWriter.println(o);
        }
    }

    private void printlnError(Object o) {
        if (errorLogWriter != null) {
            errorLogWriter.println(o);
        }
    }

    private void flush() {
        if (logWriter != null) {
            logWriter.flush();
        }
        if (errorLogWriter != null) {
            errorLogWriter.flush();
        }
    }
}

Mapatge de files

ud8.exercises.bank.persistance.rowmapper

RowMapper.java
package ud8.persistance.rowmapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public abstract class RowMapper<E> {
    public abstract E mapItem(ResultSet rs) throws SQLException;

    public List<E> map(ResultSet rs) throws SQLException {
        if (rs == null)
            return null;

        List<E> list = new ArrayList<>();
        while (rs.next()) {
            list.add(mapItem(rs));
        }
        return list;
    }
}
BankAccountRowMapper.java
package ud8.exercises.bank.persistance.rowmapper;

import ud8.exercises.bank.domain.entity.BankAccount;
import ud8.persistance.rowmapper.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;

public class BankAccountRowMapper extends RowMapper<BankAccount> {
    @Override
    public BankAccount mapItem(ResultSet rs) throws SQLException {
        String iban = rs.getString("iban");
        double balance = rs.getDouble("balance");

        return new BankAccount(iban, balance);
    }
}

Utilitats

ud8.common.utils

Nota

Aquestes classes són comunes als exemples i exercicis d'aquesta unitat.

AppPropertiesReader.java
package ud8.common.utils;

import lombok.extern.log4j.Log4j2;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

@Log4j2
public class AppPropertiesReader {
    private static final Properties properties = new Properties();

    static {
        loadProperties("application.properties"); // Carga las propiedades por defecto

        // Detectar el perfil y cargar las propiedades correspondientes
        String activeProfile = getProperty("app.profiles.active");
        if (activeProfile != null) {
            log.debug("Perfil actiu: " + activeProfile);
            loadProperties("application-" + activeProfile + ".properties");
        }
    }

    private static void loadProperties(String filename) {
        try (InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename)) {
            if (input == null) {
                System.out.println("No s'ha pogut trobar el fitxer de configuració: " + filename);
                return;
            }

            // Cargar las propiedades desde el archivo de configuración
            properties.load(input);
        } catch (IOException e) {
            System.err.println("Error al llegir el fitxer de configuració: " + filename);
        }
    }

    public static String getProperty(String key) {
        return properties.getProperty(key);
    }
}

Excepcions

ud8.common.exception

Nota

Aquestes classes són comunes als exemples i exercicis d'aquesta unitat.

ResourceNotFoundException.java
package ud8.common.exception;

public class ResourceNotFoundException extends Exception {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}
📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.