APIREST-DROPWIZARD
Indice
Iniciando Proyecto Base
- Creación de proyecto en NetBeans
 - Ajustes en el POM
 - Creando la clase de Configuración
 - Crear la clase de la aplicación
 - Crear clase ejemplo
 - Configuración ejecución en NetBeans
 - Proceso de dockerizacion
 
Adicionales
Temas a considerar
Creacion de proyecto en NetBeans
- El proyecto parent fue creado en NetBeans con la opción: 
Maven -> POM Project 

- Para los modulos se utiliza la opción: 
Maven -> Java Application 

Ajustes en el POM
- Agregar propiedad de versión de Dropwizard
    
<properties> <dropwizard.version>INSERT VERSION HERE</dropwizard.version> </properties> - Adicionar la libreria como dependencia. ```xml
 
[Arriba](#indice)
## Creando la clase de Configuracion
* Crear clase `RestConfiguration.java` base:
```java
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.Configuration;
import org.hibernate.validator.constraints.NotEmpty;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
/**
 *
 * @author ISORTEGAH
 */
public class RestConfiguration extends Configuration{
    @NotEmpty
    @JsonProperty
    private String baseUrl;
    public String getBaseUrl() {
        return baseUrl;
    }
    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }
    
    @JsonProperty("swagger")
    public SwaggerBundleConfiguration swaggerBundleConfiguration;
}
Referencia a ejemplo básico
- Adicionar al 
pom.xmldel modulorestla siguiente dependencia: 
<dependency>
    <groupId>com.smoketurner</groupId>
    <artifactId>dropwizard-swagger</artifactId>
    <version>1.0.0-rc2-1</version>
</dependency>
- Contruir el archivo de configuración 
config.yml
```yml baseUrl: http://localhost swagger: resourcePackage: com.corpfolder.rest.resources server: applicationConnectors:- type: http
port: 8080
```
Arriba
        
Crear la clase de la aplicacion
- Dentro del siguiente código se puede ver la integración de swagger como opción de exposición gráfica de los servicios. ```java import io.dropwizard.Application; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import io.federecio.dropwizard.swagger.SwaggerBundle; import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
 
 
 - type: http
port: 8080
```
Arriba
        
 
/** *
- 
    
@author ISORTEGAH */ public class ApiRestService extends Application
{ public static void main(String[] args) throws Exception { new ApiRestService().run(args); }
@Override public void initialize(Bootstrap
bootstrap) { bootstrap.addBundle(new SwaggerBundle () { protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(RestConfiguration configuration) { return configuration.swaggerBundleConfiguration; } }); } @Override public void run(RestConfiguration configuration, Environment environment) { } ```
 - 
    
Adicionar
healthCheck 
Archivo AppHealthCheck.java
public class AppHealthCheck extends HealthCheck {
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}
Adicionar al archivo ApiRestService.java
@Override
    public void run(RestConfiguration configuration,
                    Environment environment) {
        configFromAws( configuration.getAws() );
        environment.healthChecks().register("app", new AppHealthCheck());
    }
Esto evitara que se muestre el mensaje:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!    THIS APPLICATION HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW      !
!     IF IT DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE      !
!    LETTING YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH OF YOUR    !
!         APPLICATION'S DEPENDENCIES WHICH FULLY (BUT LIGHTLY) TESTS IT.       !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Referencia
Application Health Checks with DropWizard Dropwizard Core
- Adicionar plugins de contrucción del jar
 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.17</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.isortegah.rest.ApiRestService</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>com.isortegah.rest.ApiRestService</mainClass> <arguments> <argument>server</argument> <argument>config.yml</argument> </arguments> </configuration> </plugin> </plugins> </build>Crear clase ejemplo
VersionResource.java
import com.codahale.metrics.annotation.Timed;
import com.isortegah.dtos.res.version.VersionDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
 *
 * @author ISORTEGAH
 */
@Path("/version")
@Api(value = "/version")
@Produces(MediaType.APPLICATION_JSON)
public class VersionResource {
    @GET
    @Timed
    @ApiOperation(value = "Obtiene la información de la versión", position = 0)
    public VersionDTO version() {
        
       return new VersionDTO();
       
    }
}
- Adicionar modulo 
dtos 

- Crear la clase 
VersionDTO.java 
import com.fasterxml.jackson.annotation.JsonProperty;
/**
 *
 * @author ISORTEGAH
 */
public class VersionDTO {
    
    @JsonProperty
    private String nombre = "Versión 0.0.1-SNAPSHOT";
    @JsonProperty
    private String numero = "0.0.1";
    
    @JsonProperty
    private String autor = "ISORTEGAH";
    public String getAutor() {
        return autor;
    }
    public void setAutor(String autor) {
        this.autor = autor;
    }
    public String getNombre() {
            return nombre;
    }
    public void setNombre(String nombre) {
            this.nombre = nombre;
    }
    public String getNumero() {
            return numero;
    }
    public void setNumero(String numero) {
            this.numero = numero;
    }
    
}
- Adicionar la dependencia del modulo 
dtosalpom.xmldel modulorest 
<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>dtos</artifactId>
    <version>${project.version}</version>
    <type>jar</type>
</dependency>  
- Registrar el servicio en 
ApiRestService.java@Override public void run(RestConfiguration configuration, Environment environment) { environment.jersey().register(new VersionResource()); }Configuracion ejecucion en NetBeans
 - 
    
Adicionar
Configutarionsobre modulorest

 - 
    
Registrar la configuración

 - Seleccionar la opción 
Runy dentro seleccionar la configuración adicionada con los siguientes parametros:Main Class: com.isortegah.rest.ApiRestService
Arguments: server config.yml

 
Proceso de dockerizacion
- Crear 
Dockerfile 
FROM isortegah/java8:v1
EXPOSE 8080
RUN mkdir -p /app
WORKDIR /app
ADD bootstrap.sh bootstrap.sh
ADD rest/target/rest-0.1-SNAPSHOT.jar rest.jar
ADD config.yml config.yml
ENTRYPOINT ["/bin/bash", "./bootstrap.sh"]
- Crear archivo 
bootstrap.sh 
#!/usr/bin/env bash
java -jar rest.jar server config.yml
- Construcción de imagen
 
docker build -t api-rest .
- Ejecución de imagen
 
docker run -it -p 8080:8080 < imagen id >
- Ejecutar bash
 
docker exec -it < id container > /bin/bash
- Borrar contenedores finalizados
 
docker ps -a | egrep Exited | cut -d ' ' -f 1|xargs docker rm
- Borrar imagenes < none >
 
docker images | egrep none | cut -c 41-53| xargs docker rmi
Adicionales
Log4j2
- Agregar al POM del proyecto la siguiente dependencia:
 
<dependency> 
    <groupId>org.apache.logging.log4j</groupId> 
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version> 
</dependency>
- Agregar el archivo de configuración en la carpeta 
resourcedel proyecto, con el nombrelog4j.<properties|xml|yaml|json>. 

- Código Java
 
import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 
//Ejemplo de declaración de variable 
private static final Logger log = LogManager.getLogger("VersionResource");  
//Ejemplo de implementación
log.info("Se requiere servicio version"); 
Referencias
Log4j Users Guide
Referencia 1
Referencia 2
Referencia 3
Referencia 4
Referencia 5
Referencia 6
Heroku
Pre requisitos
- 
    
Instalación de Heroku Cli
 - 
    
Crear app en Heroku
 
heroku create < nombre app >
- Establecer buildpack
    
heroku buildpacks:set heroku/java - Establecer stack para despliegue con git
    
heroku stack:set heroku-18 - Establecer stack para despliegue como docker
    
heroku stack:set container 
Despliege en Heroku
- Crear archivo 
Procfile`web: java -Ddw.server.applicationConnectors[0].port=$PORT -jar rest/target/rest-0.2.0-SNAPSHOT.jar server config.yml - Desplegar app
    
git push heroku master 
Esta aplicación la podemos ver funcionando en api.isortegah.me/swagger Nota: Se encuentra desplegada como contenedor Docker.
Despliegue en heroku como docker
- Instalar plugin
    
heroku plugins:install heroku-container-registry - Login en contenedor
    
heroku container:login - Push codigo
    
heroku container:push web - Desplegar como docker
    
heroku container:release web - Correr bash en heroku
    
heroku run bashReferencia:
 
Container Registry and Runtime
Push multiple Docker images to Heroku Container Registry
| [Container Registry and Runtime | Heroku Dev Center](https://devcenter.heroku.com/articles/container-registry-and-runtime) | 
Especificar versión de Java
- Crear archivo 
system.properties"java.runtime.version=1.8" - Verificar la versión de java en Heroku
    
heroku run java -version 
JWT
- Crear modulo 
authentication
 
- Agregar dependencia al 
pom.xmldel moduloauthentication```xml 
* Para resolver el problema de ejecución del `jar` del proyecto se requiere agregar lo siguiente en el `pom.xml`del modulo `rest`.
```xml
<filters>
    <filter>
        <artifact>*:*</artifact>
        <excludes>
            <exclude>META-INF/*.SF</exclude>
            <exclude>META-INF/*.DSA</exclude>
            <exclude>META-INF/*.RSA</exclude>
        </excludes>
    </filter>
</filters>
- Verificar los cambios implementados para la funcionalidad de generar un token simple en GitHub.
 
Referencia
Aws
- Crear modulo 
aws 
- Adicionar dependencia a
 pom.xml```xml
* Adicionar al archivo `config.yml` la configuración para `aws`
```yaml
aws: 
  credentialProvider: < File|Environment > @Deprecated
  region: <Clave de region aws>
Se depreco el uso de la clase AmazonS3Client y se implemento AmazonS3Client,
para revisar la antigua documentación dirijase a la doc aws
Con la implementación de la clase AmazonS3Client, las credenciales para la conexión
a aws es man sencilla, ya que toma las credneicales del archivo ~/.aws/credentials
si existe, y de lo contrario busca las variables de ambiente.
El archivo credentials debe estar ubicado en el HOME del usuario:
~/.aws/credentials
~/ cat .aws/credentials
[default]
aws_secret_access_key=aaaa
aws_access_key_id=zzzz
Para el caso de las credenciales vía variables de ambiente el proceso es el siguiente:
- Exportar las variables:
    
export AWS_ACCESS_KEY_ID="xyz" export AWS_SECRET_ACCESS_KEY="aaa"En MacOs y Linux agregarlas en el archivo .bashrc o .bash_profile y recargarlo.
source .bash_profilePara Windows usar el comando:
set AWS_ACCESS_KEY_ID="xyz" set AWS_SECRET_ACCESS_KEY="aaa"Lo anterior para poder ejecutar el comando:
java -jar rest/target/rest-0.1-SNAPSHOT.jar server config.yml - En el archivo 
config.ymlcambiar el valorFileporEnvironment.aws: credentialProvider: Environment region: US_EAST_1 
Ejecución
Se presentan las siguientes opciones de ejecución de la imagen docker.
- De forma directa:
 
docker run -it -p 8080:8080 -e PORT=8080 -e AWS_ACCESS_KEY_ID=xyzqwd -e AWS_SECRET_ACCESS_KEY=aaa fba5ce1e06db
- Vía docker-compose:
    
- Crear archivo 
docker-compose.yml```yml version: ‘3’ services: web: image: api-rest env_file:- ./.env environment:
 - AMBIENTE=”DEV” ports:
 - “8080:8080” ```
 
 
 - Crear archivo 
 - 
    
- Crear archivo 
.envdonde registraremos las variables de ambiente 
 - Crear archivo 
 
AWS_ACCESS_KEY_ID=xyz
AWS_SECRET_ACCESS_KEY=aaa
Nota: Lo recomendable por practico y seguro, cuando ejecutemos en local, es usar el docker-compose, en el caso que estemos desarrollando podemos utilizar el archivo de credenciales.
- Despliege a heroku:
 
Agregar las variables de ambiente en settings dentro de la app en heroku.

Referencia
Instalacion
Instalación de la AWS CLI con el instalador agregado (Linux, macOS, or Unix)
Credenciales
set Environment Variables aws doc
Working with AWS Credentials Loading Credentials in Node.js from the Shared Credentials File
https://javatutorial.net/java-s3-example http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html
Docker
Environment variables in Compose
Temas a considerar
Picked up JAVA_TOOL_OPTIONS: -Xmx350m -Xss512k -Dfile.encoding=UTF-8
