PSP01_Tarea
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
KyMAN 1d85f017b8 feat: Terminada la documentación y establecida la configuración. 2 months ago
Actividad1 feat: Terminada la documentación y establecida la configuración. 2 months ago
Actividad2 feat: Terminada la documentación y establecida la configuración. 2 months ago
.gitignore feat(java): Creador de diccionarios del lenguaje inventado hecho. 2 months ago
LICENSE Initial commit 2 months ago
README.md feat: Terminada la documentación y establecida la configuración. 2 months ago
como_se_hace.md feat: Ejercicio resuelto. 2 months ago
lenguaje.sh feat(java): Creador de diccionarios del lenguaje inventado hecho. 2 months ago
tuberia.sh fix(gitignore): Comentado el '.gitignore' para evitar que se suba parcialmente el proyecto. 2 months ago

README.md

PSP01_Tarea

Este ejercicio fue hecho sin mirar el temario y entregado fuera de plazo por motivos agenos al ciclo, por lo que independientemente de resultados, agradecer al profesor a cargo de la asignatura por mirarlo igualmente pese a dichas condiciones, así por el apoyo ofrecido. También quiero que quede de aviso para otros posibles compañeros que quieran hacer uso de este contenido por posiblemente no ceñirse a lo requerido en la asignatura. Sea como sea, espero sea útil para aprender y reciclarse como lo fue para mi.

Conjunto de ejercicios para controlar entradas y salidas de una aplicación así como escritura y sincronía entre aplicaciones Java. Dicho ejercicio está publicado en la siguiente URL Git:

https://git.k3y.pw/DAM2024/PSP01_Tarea

Antes de empezar, aclarar que todos los archivos de Scripts JAVA contendrán un apartado de configuración si éstos lo requieren, en el inicio de la clase, encapsulados entre dos comentarios de línea llamados "Configuración".

ordernarNumeros

Esta aplicación simplemente cogerá una entrada de números dados por el usuario mediante el terminal donde una vez ponga cualquier cosa que no sea un valor numérico entero, éste detendrá el proceso de espera de más números, cogerá la lista de números dados y los ordenará de menor a mayor y los imprimirá por pantalla.

flowchart TD

S(["Solicitar número"])
O(["Ordenar números"])
M(["Mostrar números ordenados"])

S -->|"¿Es número?"| S
S -->|"¿No es número?"| O
O --> M

La aplicación es muy sencilla y no tiene configuración alguna. El tema del ordenamiento numérico se hace a partir del método "sort" del ArrayList donde se almacenan los números, y usado el método estático "naturalOrder" de la clase nativa Comparator. También decir que se hace uso de un objeto Scanner por simplicidad de uso para la escucha de entrada del usuario.

Resultado de ejemplo

run:
56
1
87
9
4
terminar
1
4
9
56
87
BUILD SUCCESSFUL (total time: 13 seconds)

aleatorios

Esta aplicación simplemente generará 100 valores numéricos enteros aleatorios entre 0 y 100, ambos incluídos. Una vez generados, éste los imprimirá por pantalla.

flowchart TD

G(["Generar números aleatorios"])
M(["Mostrar números aleatorios"])

G --> M

No tiene más complicación, sin embargo, dejé configurable los siguientes parámetros:

  • numero_de_numeros: Número de números enteros aleatorios que se van a crear.
  • rango_aleatorio: Tabla de dos valores numéricos enteros positivos que indican el rango en el que se generarán dichos números enteros aleatorios, incluyendo los dados. El primero ha de ser menor que el segundo.

Resultado de ejemplo

run:
97
5
65
12
91
2
14
67
56
52
81
51
9
46
16
91
56
52
14
89
20
23
71
51
38
69
100
48
100
66
2
61
73
53
25
82
30
54
40
28
83
47
69
61
92
28
39
49
58
68
83
23
14
100
25
70
25
68
88
48
92
60
16
17
79
81
4
3
56
19
71
42
89
87
23
93
61
20
61
15
36
68
87
80
13
3
94
77
53
34
53
80
58
24
6
24
45
42
47
37
BUILD SUCCESSFUL (total time: 0 seconds)

Tubería

Las dos aplicaciones anteriores pueden coexistir y funcionar entre ellas mediante una tubería en un terminal o consola de comandos, mandando la salida de la aplicación aleatorios contra la entrada de ordenarNumeros. El comando sería el siguiente:

#!/bin/bash
directorio=`dirname $(readlink -f "$0")`
java -jar $directorio/Actividad1/aleatorios/dist/aleatorios.jar | java -jar $directorio/Actividad1/ordenarNumeros/dist/ordenarNumeros.jar 

En el Script, también existente en el proyecto, establece el directorio raíz donde se encuentra, que viene siendo el Path raíz del proyecto, y luego cogerá el Path relativo a cada JAR de cada aplicación. También puede llamarse directamente, como en el ejemplo siguiente, donde se usará una ruta relativa:

#!/bin/bash
java -jar Actividad1/aleatorios/dist/aleatorios.jar | java -jar Actividad1/ordenarNumeros/dist/ordenarNumeros.jar 
flowchart TD

A[aleatorios]
O[ordenarNumeros]

A --> O

Resultados de ejemplo

kyman@kyman-GS75-9SE:/home/DAM2024/PSP01_Tarea$ ./tuberia.sh 
0
1
2
4
5
6
7
8
11
12
12
13
14
14
14
19
20
22
25
26
27
27
28
29
29
30
30
32
33
34
34
37
37
38
38
40
41
41
41
43
44
45
46
46
46
48
49
50
50
51
51
51
51
53
55
57
58
60
61
62
64
64
65
65
67
68
68
68
68
70
71
71
71
73
75
75
77
78
79
81
82
82
83
83
84
86
86
87
88
88
88
92
92
93
96
96
97
98
99
100
kyman@kyman-GS75-9SE:/home/DAM2024/PSP01_Tarea$ java -jar Actividad1/aleatorios/dist/aleatorios.jar | java -jar Actividad1/ordenarNumeros/dist/ordenarNumeros.jar 
0
0
2
2
2
3
4
4
5
5
5
6
8
8
8
9
9
11
12
13
13
16
16
17
17
17
21
25
26
26
26
26
27
30
31
33
33
34
34
36
37
38
38
38
40
41
43
43
44
45
45
46
47
47
48
49
49
50
50
52
53
54
55
55
56
56
61
63
63
65
65
66
66
68
68
68
70
75
77
77
79
79
82
83
83
85
87
87
89
90
90
91
94
94
95
95
96
96
100
100
kyman@kyman-GS75-9SE:/home/DAM2024/PSP01_Tarea$ 

lenguaje

Esta aplicación crea un diccionario de un idioma inventado a partir de juntar, aleatoriamente, letras. Para su ejecución requiere de 2 parámetros de entrada, los cuales son:

  1. El número de palabras a crear.
  2. El Path donde se almacenará el diccionario.

Por defecto, ambos parámetros están definidos en la configuración de la aplicación a 40 palabras y el Path del fichero diccionario en el raíz del proyecto con el nombre "diccionario.txt".

La idea es que el programa añada al fichero diccionario cada palabra generada, recargando el fichero, añadiendo al Buffer la nueva palabra en una nueva línea, escribiendo el fichero y cerrando el Buffer.

flowchart TD

C{"Crear nueva palabra aleatoria"}
D["Archivo diccionario"]
O["Objeto File"]
A{"Crear archivo diccionario"}
B[Buffer]
P["Nueva palabra"]
E{"Escribir archivo diccionario"}

C -->|Crear| P
C --> D
D -->|"Abrir con"| O
O -->|"Sí existe"| B
O -->|"No existe"| A
A --> B
P -->|"Añadir en"| B
B --> E

La creación de la palabra se basa en un diccionario String que contendrá los caracteres a usar que se encuentra en la configuración. Para su creación se establecen dos condiciones: que sea al menos de 3 caracteres; y se vayan añadiendo caracteres si la condición aleatoria así lo determine. La probabilidad de nueva letra no es más que un "Math.random" condicionado a un valor decimal entre 0 y 1. A mayor sea el número más letras probables contendrá la nueva palabra.

flowchart TD

P[Palabra]
C{"length < 3 || \nRand < probabilidad"}
L["Nueva letra"]
X(["Nueva palabra creada"])

P -->|Mientras| C
C -->|Sí| L
C -->|No| X
L -->|"Se añade a"| P

Socket

En el siguiente ejercicio a éste, se especifica literalmente que lance al menos 10 instancias de la aplicación "lenguaje", donde entiendo que la aplicación es el JAR de la aplicación "lenguage". Indagué un poco sobre Java, viendo la imposibilidad de éste de analizar si un fichero está en uso o no, donde hay librerías que permiten un uso de bloqueo de ficheros o detectar un uso por bloqueo mediante Excepción, pero en ningún caso me funcionó cara la mera apertura del fichero, por lo que me vi en la obligación de crear un Socket de comunicación bidireccional entre las diferentes instancias de la aplicación "lenguaje" como clientes, sobre un servidor "colaborar", quien contendría el semáforo entre aplicaciones mediante un simple valor Booleano que determine si el archivo está siendo usado por alguna de las instancias o no, donde en caso de estar en uso, ésta espere un tiempo aleatorio para volver a intentar la petición.

flowchart TD

subgraph lenguage

    X{"Crear nueva palabra"}
    S[Socket]
    E{Esperar}
    W{"Escribir diccionario"}
    L{"Liberar diccionario"}

    E --> S
    X --> S

end
C[Colaborar]

S -->|"¿Está en uso?"| C
C -->|Sí| E
C -->|No| W
W --> L
L -.-> C
L --> X

Si no fuese la ejecución de instancias de aplicación y sí de simples instancias de la clase "Lenguaje", el formato sería distinto, siendo regulado por semáforos o un simple Booleano que condicione, incluso, al estar trabajando en este caso sobre objetos, directamente con un "wait" donde se irían desbloqueando los procesos entre ellos, simplificando enormemente la aplicación.

Mediante este sistema evitamos que la sobreescritura por parte de cualquiera de las instancias de aplicación ejecutadas exista, permitiendo un orden mediante un protocolo de semáforos a un sólo proceso.

La aplicación entiende que si existe el servidor Socket de "colaborar", éste ha de regularse de esta forma; de lo contrario, actuará como estaba predicho anteriormente.

Es importante mencionar que hay una serie de salidas que determinan qué hace el Socket tanto para uso local como para uso remoto contra "colaborar".

Configuración

Los parámtros de configuración para esta aplicación son los siguientes:

  • puerto: Puerto de red del Socket servidor "colaborar".
  • host: Host de red del Socket servidor "colaborar".
  • numero_de_palabras: Número de palabras por defecto a crear en caso de tener una entrada vacía.
  • path: Path relativo al Path del JAR "lenguaje.jar" donde se almacenará el diccionario.
  • alfabeto: String con los caracteres a usar para crear las nuevas palabras.
  • probabilidad_nueva_letra: Valor decimal comprendido entre 0 y 1 que determina la probabilidad de añadir un nuevo caracter a la nueva palabra.

colaborar

Esta aplicación ejecutará varias instancias de la aplicación "lenguage" para que éstas escriban, de forma ordenada y sincronizada, un diccionario común. Para llevar a cabo dicha tarea se hará uso de un Socket que gestione, a modo de semáforo de un único proceso, el acceso al fichero diccionario de todas las instancias ejecutadas de la aplicación. Todas estas instancias serán lanzadas por la propia aplicación "colaborar". Uba vez terminen todas las instancias de almacenar sus palabras al diccionario, la aplicación mostrará un mensaje indicando que terminó y que presiones "Enter" para poder cerrar la aplicación.

Si no fuese la ejecución de instancias de aplicación y sí de simples instancias de la clase "Lenguaje", el formato sería distinto, siendo regulado por semáforos o un simple Booleano que condicione, incluso, al estar trabajando en este caso sobre objetos, directamente con un "wait" donde se irían desbloqueando los procesos entre ellos, simplificando enormemente la aplicación.

El programa no se cierra por el hecho de que cuenta con una entrada de terminal por si se quiere cerrar la aplicación mediante una orden. Si se termina la ejecución del programa, queda el objeto Scanner abierto, el cual, al ser de interactuación humana, éste ha de ser cerrado por el usuario, y de ahí que muestr el mensaje pidiendo que se presione "Enter".

flowchart TD

subgraph colaborar
    P[Permiso]
    O{"Ocupar diccionario"}
    OS([Sí])
    ON([No])
    D{"Desocupar diccionario"}
    C{Cerrar}
end
L[lenguage]

L -->|"¿Tiene?"| P
P --> OS
OS --> O
OS -->|"Tiene permiso"| L
P --> ON
ON -->|"No tiene permiso"| L
L -->|"Nueva palabra añadida"| D
L -->|Terminó| C

Las instancias de la aplicación "lenguaje" son lanzadas tras haber lanzado el Socket servidor y el terminal. El caso de que el Socket servidor dé un error de inicio, éste lo mostrará y no lanzará nada más, cerrando la aplicación automáticamente.

flowchart TD

S{{"¿Inició el servidor?"}}
T{{"Inicia el terminal"}}
I{{"Ejecuta las instancias cliente"}}
E{{"Imprimir error"}}
SI([Sí])
NO([No])

S --> SI
SI --> T
SI --> I
S --> NO
NO --> E

Si el usuario introduce en la terminal de la aplicación cualquiera de las opciones "close", "cerrar", "bye", "exit" o "terminar", la aplicación mandará orden de cierre a las aplicaciones cliente y se cerrará ella misma.

Hay elementos que imprimirán por la terminal indicaciones de lo que está haciendo la aplicación durante su ejecución, mayormente para controlar el correcto funcionamiento de los Socket. También imprimirá lo que impriman sobre terminal las instancias de la aplicación "lenguaje" ejecutadas.

El cierre automático de la aplicación cuando los clientes terminan su actividad se lleva a cabo a partir de una variable de control la cual viene siendo un valor numérico entero con valor por defecto 0 pero que a medida que se traen mensajes de cierre de los clientes, éste irá incrementándose. Cuando éste sea igual al número de clientes, la aplicación entederá como que todos los clientes temrinaron y cesará su actividad.

La configuración de esta aplicación es la siguiente:

  • numero_instancias: Númerom de instancias de la aplicación "lenguaje" va a ejecutar simultáneamente.
  • path_absoluto: Path absoluto del proyecto raíz. ¡Ojo! No del proyecto Java, sino el proyecto completo del ejercicio.
  • lenguaje_path: Path de la aplicación JAR "lenguaje.jar".
  • puerto: Puerto de trabajo del Socket.

Documentación

En el ejercicio se establecen ciertas normas cara lo que viene siendo la documentación del ejercicio, pero por falta de tiempo y las circunstancias descritas al inicio de este documento, me vi en la decisión de montar toda documentación requerida sobre MarkDown y así integrarlo dentro del proyecto Git para facilitar tanto su acceso como su visibilidad mediante los componentes integrados en éste como gráficos o formatos de texto rápido mediante marcas por caracter.