ServerStudioMedico.java
/* 
 * Andrea Caravano (www.andreacaravano.net) 
 * 
 * Esercizio 3: "StudioMedico" 
 * Descrizione: Uno studio medico ha adottato un infrastruttura di rete che prevede che, per ogni medico, 
 * esista un file di testo contenente le informazioni personali (nome, cognome, data di nascita e città di nascita) dei pazienti in cura (si suppone tali informazioni non contengano spazi e siano separate da Whitespace). 
 * Ogni medico, in seguito ad autenticazione mediante nome utente e password (memorizzate su linee 
 * separate all’inizio del file), può effettuare due operazioni: 
 * 1)   Aggiunta nuovo paziente in cura 
 * 2)   Consultazione elenco completo dei pazienti 
 * N.B.: Se il nome utente specificato dal client non esiste, si utilizzano il nome utente 
 * specificato per creare un nuovo file, corrispondente al nuovo medico. 
 * Un possibile file di esempio è il seguente: 
 * <file “rossi.txt”>: 
 * mario 
 * passwordmario 
 * Giuseppe Verdi 01/02/1980 Milano 
 * Carlo Russo 03/04/1990 Roma 
 * 
 * Possibile soluzione 
 * Componente Server 
 * 
 * N.B.: L'esercizio scaturisce dalla sola fantasia dell'autore e intende rappresentare una applicazione didattica. 
 * I dettagli in esso contenuti potrebbero non essere corrispondenti alla realtà e intendono valutare le abilità nella gestione delle strutture dati proposte. 
 */

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Paziente {
    private String cognome, nome, dataNascita, cittaNascita;

    Paziente(String cognome, String nome, String dataNascita, String cittaNascita) {
        this.cognome = cognome;
        this.nome = nome;
        this.dataNascita = dataNascita;
        this.cittaNascita = cittaNascita;
    }

    @Override
    public String toString() {
        return String.format("%s %s %s %s%n", cognome, nome, dataNascita, cittaNascita);
    }

    public String stampaPaziente() {
        StringBuilder SB = new StringBuilder();
        SB.append(String.format("Cognome: %s%n", cognome));
        SB.append(String.format("Nome: %s%n", nome));
        SB.append(String.format("Data di nascita: %s%n", dataNascita));
        SB.append(String.format("Città di nascita: %s", cittaNascita));
        return SB.toString();
    }
}

public class ServerStudioMedico {
    static final int PORTALISTEN = 9000;
    static ExecutorService esecutore = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        try (ServerSocket procServer = new ServerSocket(PORTALISTEN)) {
            System.out.format("Processo server avviato con il seguente indirizzo di socket: %s%n", procServer.getLocalSocketAddress());
            while (true) {
                try {
                    Socket tempSocket = procServer.accept();
                    esecutore.execute(() -> {
                        try (Socket varClient = tempSocket) {
                            System.out.format("Thread ID = %d - Indirizzo di socket del client: %s%n", Thread.currentThread().getId(), varClient.getRemoteSocketAddress());
                            avviaComunicazione(varClient);
                        } catch (IOException e) {
                            System.err.format("Errore di avvio della comunicazione: %s%n", e.getMessage());
                        }
                    });
                } catch (IOException e) {
                    System.err.format("Errore nella creazione di nuovi socket: %s%n", e.getMessage());
                }
            }
        } catch (IOException e) {
            System.err.format("Errore lato server: %s%n", e.getMessage());
        }
    }

    private static void avviaComunicazione(Socket varClient) {
        try (
                BufferedReader BR = new BufferedReader(new InputStreamReader(varClient.getInputStream(), "UTF-8"));
                PrintWriter PW = new PrintWriter(new OutputStreamWriter(varClient.getOutputStream(), "UTF-8"), true)
        ) {
            String nomeUtente = BR.readLine();
            String password = BR.readLine();
            BufferedWriter BW = null;
            if (new File(String.format("%s.txt", nomeUtente)).exists()) {
                Scanner S = new Scanner(new FileReader(String.format("%s.txt", nomeUtente)));
                if (nomeUtente.equals(S.nextLine()) && password.equals(S.nextLine())) {
                    PW.println("100"); // Tratto da HTTP: "Continue"
                } else {
                    varClient.close();
                    throw new IOException("Nome utente o password errati.");
                }
            } else {
                BW = new BufferedWriter(new FileWriter(String.format("%s.txt", nomeUtente)));
                BW.write(String.format("%s%n", nomeUtente));
                BW.write(String.format("%s%n", password));
                BW.close();
                PW.println("201"); // Tratto da HTTP: "Created"
            }
            int sceltaUtente = Integer.valueOf(BR.readLine());
            BW = new BufferedWriter(new FileWriter(String.format("%s.txt", nomeUtente), true));
            if (sceltaUtente == 1) {
                Scanner datiPaziente = new Scanner(BR.readLine());
                Paziente p = new Paziente(datiPaziente.next(), datiPaziente.next(), datiPaziente.next(), datiPaziente.next());
                BW.write(p.toString());
                PW.println("200"); // Tratto da HTTP: "OK"
                BW.close();
            } else if (sceltaUtente == 2) {
                BW.close();
                Scanner S = new Scanner(new FileReader(String.format("%s.txt", nomeUtente)));
                S.nextLine();
                S.nextLine();
                // Salto due righe, trattandosi di nome utente e password, che non mi interessa leggere.
                while (S.hasNext()) {
                    Paziente p = new Paziente(S.next(), S.next(), S.next(), S.next());
                    PW.println(p.stampaPaziente());
                }
                PW.println("");
            } else {
                PW.println("405"); // Si adotta, come in HTTP, il codice 405 (Method Not Allowed), indicante la scelta non valida.
            }
        } catch (IOException e) {
            System.err.format("Errore di I/O: %s%n", e.getMessage());
        }
    }
}