Cliente – Suministrador con Idea

Ejercicio Productor – Consumidor resuelto con IntelliJ Idea 2022.3

El proyecto se llama Cliente-Suministrador

Constantes.java

public class Constantes {
    public static final String FICHEROLOG = "ficheroLog.txt";
    public static final String INTERCAMBIO = "numeros.txt";
    public static final String FICHEROERRORES = "errores.txt";
    public static final int REPETICIONES = 10;
    
    //El proyecto se llama Cliente-Suministrador
    public static final String CARPETA = "./out/production/Cliente-Suministrador/";
}

Suministrador.java

public class Suministrador {
    public static void main(String[] args) throws IOException {
        int cuenta = 0;
        FileLock bloqueo = null;
        RandomAccessFile raf = null;

        //Rediregimos la salida y error estándar al fichero de log
        try {
            PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(Constantes.FICHEROLOG),true)), true);
            System.setOut(ps);
            System.setErr(ps);
        } catch (FileNotFoundException exp) {
            System.out.println(exp.getCause());
            exp.printStackTrace();
        }

        while (cuenta <= Constantes.REPETICIONES) {
            try {
                raf = new RandomAccessFile(Constantes.INTERCAMBIO, "rwd"); //Abrimos el fichero
                //Sección crítica
                bloqueo = raf.getChannel().lock();
                System.out.println("Suministrador: Entra en la sección");
                if (raf.length() == 0) {
                    int aleatorio = generarNumeroAleatorioEntre(1, 100);
                    raf.writeInt(aleatorio);
                    System.out.println("Suministrador: dato escrito " + aleatorio);
                    cuenta ++;
                } else
                    System.out.println("Suministrador: no puede escribir");
                System.out.println("Suministrador: Sale de la sección");
                bloqueo.release();
                bloqueo = null;
                //Fin sección crítica
                Thread.sleep(1000); //Simulamos tiempo de creación del dato
            } catch (Exception e) {
                System.err.println("Suministrador. Error al acceder al fichero.");
                System.err.println(e.toString());
            } finally {
                try {
                    if (bloqueo != null) bloqueo.release();
                    if (raf != null) raf.close();
                } catch (IOException exp4) {
                    System.out.println(exp4.getCause());
                    exp4.printStackTrace();
                }
            }
        }
        System.out.println("Suministrador: FIN");
    }
    private static int generarNumeroAleatorioEntre(int minimo, int maximo) {
        return  (int) (Math.random() * (maximo + 1 - minimo)) + minimo;
    }
}

Cliente.java

public class Cliente {
    /**
     * @param args Argumento [0] da el número de cliente, lo recibe al lanzarlo con ProcessBuilder
     */
    public static void main(String[] args) {
        int numeroCliente = Integer.parseInt(args[0]);
        RandomAccessFile raf = null;
        FileLock bloqueo = null;
        int cuenta = 1;
        int valor;

        //Rediregimos salida y error estándar a un fichero
        PrintStream ps = null;
        try {
            ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(Constantes.FICHEROLOG),true)), true);
            System.setOut(ps);
            System.setErr(ps);
        } catch (FileNotFoundException exp) {
            System.out.println(exp.getCause());
            exp.printStackTrace();
        }

        while  (cuenta <= Constantes.REPETICIONES) {// Leemos del fichero las repeticiones realizadas por el suministrador
            try {
                raf = new RandomAccessFile(Constantes.INTERCAMBIO, "rwd"); //Abrimos el fichero
                //Sección crítica
                bloqueo = raf.getChannel().lock();
                System.out.println("Cliente " + numeroCliente + ": entra en la sección");
                if (raf.length() > 0) {
                    valor = raf.readInt();
                    System.out.println("Cliente " + numeroCliente + ": lee " + valor);
                    raf.setLength(0);
                    cuenta ++;
                } else
                    System.out.println("Cliente: " + numeroCliente + ": no puede leer");
                System.out.println("Cliente " + numeroCliente + " sale de la sección");
                bloqueo.release();
                bloqueo = null;
                //Fin sección crítica
                Thread.sleep(2000);//simulamos tiempo de procesamiento del dato
            } catch (IOException e) {
                System.err.println("Cliente " + numeroCliente + ": Error al acceder al fichero.");
                System.err.println(e.toString());
            } catch (OverlappingFileLockException ex) {
                System.err.println("Cliente " + numeroCliente + ": Error en el bloqueo del fichero.");
                System.err.println(ex.toString());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (bloqueo != null) bloqueo.release();
                    if (raf != null) raf.close();
                } catch (Exception e2) {
                    System.err.println("Cliente " + numeroCliente + ": Error al cerrar el fichero.");
                    System.err.println(e2.toString());
                    System.exit(1);  //Si hay error, finalizamos
                }
            }
        }
        System.out.println("Cliente " + numeroCliente + " FIN");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        //fecha usada para el log de salida
        Date fecha = new Date();
        SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        String hora = formato.format(fecha);
        // La lista de los procesos y los contadores
        ArrayList<Process> listaProcesos = new ArrayList<>();
        int suministrador = 0;
        int cliente = 0;

        try {// Eliminamos el contenido del fichero al entrar por si tiene un 0
            RandomAccessFile fichero = new RandomAccessFile(Constantes.CARPETA + Constantes.INTERCAMBIO, "rwd");
            fichero.setLength(0);
            fichero.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //Rediregimos salida y error estándar a un fichero, si no la salida de todos los procesos se mezclaría con el menú
        try {
            PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File(Constantes.CARPETA + Constantes.FICHEROLOG),false)), true);
            ps.println("-----------------" + hora + "-----------------------");
        } catch (FileNotFoundException exp) {
            System.out.println(exp.getCause());
            exp.printStackTrace();
        }

        int opcion = 0;
        do {
            opcion = mostrarMenuPrincipal(); // Ménu de opciones
            switch (opcion) {
                case 1:
                    if (suministrador == 0) { //el suministrador solo se puede lazar una vez
                        listaProcesos.add(lanzadorProcesos("Suministrador", 1));
                        suministrador ++;
                        System.out.println("Suministrador " + suministrador + " lanzado");
                    } else{
                        System.out.println("Solo se puede lanzar un Suministrador y ya hay uno ejecutándose");
                    }
                    break;
                case 2:
                    cliente ++;
                    listaProcesos.add(lanzadorProcesos("Cliente", cliente));
                    System.out.println("Cliente " + cliente + " lanzado");
                    break;
                case 3:
                    try {
                        esperarFinalizacion(listaProcesos);
                    } catch (InterruptedException e) {
                        System.out.println(e.getMessage());
                    }
                    System.out.println("... procesos finalizados");
                    System.out.println("Ejecuci\u00f3n finalizada");
                    break;
            }
        } while (opcion != 3);

    }

    /**
     * Menú principal de opciones
     * @return
     */
    private static int mostrarMenuPrincipal() {

        int opcion = 1;
        boolean leido = false;
        int numero = 0;
        Scanner teclado = null;

        System.out.println (
                "\nSeleccione una opci\u00f3n:"
                        + "\n1. Lanzar Suministrador"
                        + "\n2. Lanzar Cliente"
                        + "\n3. Terminar"
                        + "\nIndique un número del 1 al 3:"
        );
        do {
            try {
                teclado = new Scanner(System.in);
                opcion = teclado.nextInt();
                leido = true;
            } catch (Exception e) {
                System.out.println("Error: No es un número entero válido.\n");
            }
        } while (!leido);

        return opcion;
    }

    /**
     * Lanzador de procesos que recibe de entrada un comando y un número usado para diferenciarlos.
     * Ejecuta el comando y devuelve un proceso.
     */
    public static Process lanzadorProcesos(String comando, int n) {
        ProcessBuilder pb ;
        Process process = null;

        try {
            pb = new ProcessBuilder("java",
                    comando,
                    String.valueOf(n));
            pb.directory(new File(Constantes.CARPETA));
            pb.redirectError(new File(Constantes.CARPETA + Constantes.FICHEROERRORES));
            process = pb.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return process;
    }

    /**
     * Recibe una lista de procesos y espera hasta que todos estan cerrados para devolver true
     * @param listaProcesos array Process
     */
    private static void esperarFinalizacion(ArrayList<Process> listaProcesos) throws InterruptedException {
        System.out.print("Procesos en ejecución:\n");
        boolean fin = false;
        int contador = 0;

        if (listaProcesos.size() > 0)
            while (!fin) {
                contador = 0;
                for (Process proceso : listaProcesos) {
                    if (proceso.isAlive()) {
                        System.out.println(proceso.info());
                        contador ++;
                        System.out.println(contador);
                        proceso.waitFor(); // Esperar a que termine el proceso
                    }
                    if (contador == 0)
                        fin = true;
                }
                Thread.sleep(1000);
            }
    }
}

Para ver en tiempo real el contenido del fichero de log se puede usar en consola el comando tail:

tail -f out/production/Cliente-Suministrador/ficheroLog.txt

Código del Cliente-Suministrador con IntelliJ Idea

 

 

Deja una respuesta