Skip to content

Commit

Permalink
feat: added filesystem
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasanchez committed May 31, 2021
1 parent 3e7e568 commit 166dadd
Show file tree
Hide file tree
Showing 31 changed files with 1,572 additions and 0 deletions.
131 changes: 131 additions & 0 deletions 04-lecture/filesystem/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
Sistema de Achivos
==================

Esta es el código base para el ejercicio de File System (Sistema de Archivos). Está diseñado para:

* Java 8. :warning: Si bien el proyecto no lo limita explícitamente, el comando `mvn verify` no funcionará con versiones mas modernas de Java.
* JUnit 5. :warning: La versión 5 de JUnit es la más nueva del framework y presenta algunas diferencias respecto a la versión "clásica" (JUnit 4). Para mayores detalles, ver:
* [Apunte de herramientas](https://docs.google.com/document/d/1VYBey56M0UU6C0689hAClAvF9ILE6E7nKIuOqrRJnWQ/edit#heading=h.dnwhvummp994)
* [Entrada de Blog (en inglés)](https://www.baeldung.com/junit-5-migration)
* [Entrada de Blog (en español)](https://www.paradigmadigital.com/dev/nos-espera-junit-5/)
* Maven 3.3 o superior

# El enunciado

Un equipo de desarrollo acaba de implementar un novedoso y revolucionario sistema de archivos: un conjunto de objetos
que nos permiten abrir y cerrar archivos (binarios), y leerlos o escribirlos secuencialmente. Sin embargo, no se esmeraron mucho en que la interfaz entrante al sistema sea fácil de usar:

```java
public interface LowLevelFileSystem {
int openFile(String path);

void closeFile(int fd);
int syncReadFile(int fd, byte[] bufferBytes, int bufferStart, int bufferEnd);
void syncWriteFile(int fd, byte[] bufferBytes, int bufferStart, int bufferEnd);
void asyncReadFile(int fd, byte[] bufferBytes, int bufferStart, int bufferEnd,
Consumer<Integer> callback);
void asyncWriteFile(int fd, byte[] bufferBytes, int bufferStart, int bufferEnd,
Runnable callback);
}
```
(ver archivo `fs/LowLevelFileSystem.java`)

Como ven esta interfaz entrante (representada por una __interface__ Java) cumple lo solicitado, pero presenta un bajo nivel de abstraccion y no es por tanto fácil de usar.


Entonces nos solicitaron que diseñemos una mejor interfaz entrante a este sistema, que pueda usar un programador (una API, application programming interface) que sea de mayor nivel de abstracción y más simple de usar. Esta estará conformada por uno o más componentes (interfaces, objetos, clases, etc) que tendremos que diseñar.

Ademas, nos pidieron que implementemos esta intefaz de forma que todas las operaciones que se hagan contra esta API terminen ejecutando las operaciones de la interfaz de bajo nivel del sistema de archivos.

Sin embargo, los requerimientos son un poco abiertos. Nos han señalado las siguientes cosas:
* Este API debe ser "fácil" de usar para un programador: debería ser clara, aprovechar el paradigma de objetos, ocultar detalles que no nos aportan y presentar buenas abstracciones.
* No es necesario que exponga una única __interface__ tipo fachada.
* Debe usar a la interfaz entrante original que nos dieron, pero no modificarla.
* Debe ser robusta, presentando un buen manejo de errores
* Esta API debe permitr como mínimo:
* abrir un archivo para lecto escritura
* cerrar un archivo
* escribir sincrónicamente un bloque de n bytes de archivo
* leer sincrónicamente un bloque de n bytes de un archivo
* leer asincrónicamente un bloque de n bytes de un archivo
* escribir asincrónicamente un bloque de n bytes de un archivo
* ¡OJO! Es importante que el API tenga un buen manejo de errores
* Esta API que diseñaremos será básicamente un adaptador, es decir, no agregará funcionalidad al sistema de archivos original,
sino que tan solo expondrá una mejor interfaz entrante. Es decir, ahora aquella interfaz entrante original será para nosotres
la interfaz saliente del pequeño sistema adaptador que vamos a diseñar.

```
+---+ +-----------------+
Componentes ---> |API|--> |File System Posta|
que usan +---+ +-----------------+
al file system ^
|
+--- nosotres diseñaremos esto
```
Entonces, tenemos como tarea "embellecer" al sistema de archivos. Y como segunda tarea, dar un ejemplo de uso del API para los siguiente casos:
* Tenemos que leer de un archivo 3 campos: el primero de 4 bytes (C0), el segundo de 1 byte (C1), el tercero de 5 bytes (C2). Y escribir en otro archivo C0, un bloque 0x0, 0x10, 0x0, y luego C1 y C2.
* Tenemos que leer un archivo completo, y escribirlo en otro archivo, en bloques de igual tamaño parametrizable.

Los ejemplos tambien tenemos que plantearlos nosotres, en forma de tests.

Finalmente, como nuestro cliente es bastante quisquilloso quiere ver formas alternativas de solucionar las lecturas sincrónicas y asincrónicas, para compararlas y ver cuales le gustan más.

## Notas

* no nos interesa lidiar con problemas de concurrencia. Asumimos que ya los resuelve el sistema de archivos.
* para poder testear vamos a necesitar usar mocks. [Mockito](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html) ya se encuentra agregada como dependencia
* hay algunos tests implementados que les pueden servir de puntapié. Obviamente no andan, tienen que implementar el código faltante
* hay algunos tests que sólo están enunciados, pero no están implementados están implementados. Nuevamente, tienen que implementarlos
* [acá](https://docs.google.com/document/d/1l22DXR13J3XlcEkdwWsba5zg8gl_XwFA7cWf_LIOHHk/edit#) hay una solución propuesta que les puede guiar en la implementación. Tengan en cuenta que no contempla todos los requerimientos de forma detallada (en particular, las escrituras y validaciones no están desarroladas), pero creemos que servirá como orientación en gran medida.
* [acá](https://www.youtube.com/watch?v=-p7_NUDLRB0&list=PLTpxfh7PF3OpJSMNNPaYxLJii3Xm7PPA_&index=3) hay unos videos introductorios a Mockito
* [y acá](https://docs.google.com/document/d/1467Gc-adARJZZhVAdgazdCeHWRzCUJg6CfMD3nkhmG4/edit#) hay un breve apunte con un resúmen de las capacidades de Mockito


## Bonus

Opcionalmente, esta interfaz debería permitir:

* Saber si una ruta (path) denota un archivo regular
* Saber si una ruta (path) denota un directorio
* Saber si una ruta (path) existe (sin importar qué sea)


# Ejecutar tests

```
mvn test
```

# Validar el proyecto de forma exahustiva

```
mvn clean verify
```

Este comando hará lo siguiente:

1. Ejecutará los tests
2. Validará las convenciones de formato mediante checkstyle
3. Detectará la presencia de (ciertos) code smells
4. Validará la cobertura del proyecto

# Entrega del proyecto

Para entregar el proyecto, crear un tag llamado `entrega-final`. Es importante que antes de realizarlo se corra la validación
explicada en el punto anterior. Se recomienda hacerlo de la siguiente forma:

```
mvn clean verify && git tag entrega-final && git push origin HEAD --tags
```

# Configuración del IDE (IntelliJ)

1. Tabular con dos espacios: ![Screenshot_2021-04-09_18-23-26](https://user-images.githubusercontent.com/677436/114242543-73e1fe00-9961-11eb-9a61-7e34be9fb8de.png)
2. Instalar y configurar Checkstyle:
1. Instalar el plugin https://plugins.jetbrains.com/plugin/1065-checkstyle-idea:
2. Configurarlo activando los Checks de Google y la versión de Checkstyle `== 8.35`: ![Screenshot_2021-04-09_18-16-13](https://user-images.githubusercontent.com/677436/114242548-75132b00-9961-11eb-972e-28e6e1412979.png)
3. Usar fin de linea unix
1. En **Settings/Preferences**, ir a a **Editor | Code Style**.
2. En la lista **Line separator**, seleccionar `Unix and OS X (\n)`.
![Screenshot 2021-04-10 03-49-00](https://user-images.githubusercontent.com/11875266/114260872-c6490c00-99ad-11eb-838f-022acc1903f4.png)
136 changes: 136 additions & 0 deletions 04-lecture/filesystem/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>

<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>ar.edu.utn.frba.dds</groupId>
<artifactId>FileSystem</artifactId>
<version>1.0-SNAPSHOT</version>

<name>FileSystem</name>
<url>https://github.com/dds-utn</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<configLocation>google_checks.xml</configLocation>
<violationSeverity>warning</violationSeverity>
<violationIgnore>
MissingJavadocMethod,
MissingJavadocPackage,
MissingJavadocType,
NonEmptyAtclauseDescription,
JavadocParagraph,
JavadocTagContinuationIndentation,
SummaryJavadoc
</violationIgnore>
</configuration>
<executions>
<execution>
<id>Validar Formateo</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.2.0</version>
<configuration>
<xmlOutput>true</xmlOutput>
<threshold>Low</threshold>
<effort>default</effort>
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
<failOnError>true</failOnError>
</configuration>
<executions>
<execution>
<id>Validar Code Smells</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>Validar Cobertura</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.75</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
8 changes: 8 additions & 0 deletions 04-lecture/filesystem/spotbugs-exclude.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Match>
<Bug pattern="EI_EXPOSE_REP"/>
<Class name="fs.Buffer"/>
</Match>

</FindBugsFilter>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fs.exceptions.file;

/**
* File exceptions.
*/
public class CanNotCloseFileException extends RuntimeException {

/**
* Throws a new Can not close file.
*
* @param cause the cause of failure.
* @throws RuntimeException if file could not be closed.
*/
public CanNotCloseFileException(String cause) {
super("Couldn't close file: " + cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fs.exceptions.file;

/**
* File exceptions.
*/
public class CanNotOpenFileException extends RuntimeException {

/**
* Throws a new Can not open file.
*
* @param cause the cause of failure.
* @throws RuntimeException if file could not be opened.
*/
public CanNotOpenFileException(String cause) {
super("Couldn't open file: " + cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fs.exceptions.file;

/**
* File exceptions.
*/
public class CanNotReadFileException extends RuntimeException {

/**
* Throws a new Can not read file.
*
* @param cause the cause of failure.
* @throws RuntimeException if file could not be read.
*/
public CanNotReadFileException(String cause) {
super("Couldn't read file: " + cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package fs.exceptions.file;

/**
* File exception.
*/
public class CanNotWriteFileException extends RuntimeException {

/**
* Throws a new Can not write file.
*
* @param cause the cause of failure.
* @throws RuntimeException if file could not be write.
*/
public CanNotWriteFileException(String cause) {
super("Couldn't write file: " + cause);
}

}
Loading

0 comments on commit 166dadd

Please sign in to comment.