Tips, Soluciones y Novedades en Tecnología

12/08/2018

URL Firmadas en AWS





Hoy veremos como acceder a nuestros archivos privados de AWS S3 desde CloudFront, tenemos un Bucket en S3 con archivos privados, es decir sin acceso publico.



Como puedo descargar el archivo desde una URL?



La solución que voy a compartir es mediante URL firmadas, este mecanismo permite a nuestro que archivo solo pueda ser accedido por la URL firmada e identificada, aplicando un tiempo para acceder y pasado ese periodo la URL quedará inaccesible.





Para ello vamos a ejecutar una serie de Pasos:



1: Crear un Bucket



Como primero paso vamos a crear un Bucket













 Creamos nuestro Bucket "mybucket-ejemplo"



2: Cargar archivos al Bucket









 Cargamos un archivo a nuestro buecket







Si intentamos acceder a nuestro archivo, vemos que no es posible, por que al subir un archivo por defecto es privado.



3: Crear una distribución a CloudFront



 Ahora debemos dirigir al servicio CloudFront para crear una nueva distribución teniendo en cuenta cierta configuración.











 Como podemos observar en la imagen adjunta, se ha enumerado 4 puntos en la primera sección del formulario, explico cada una.




  1. Seleccionar el Bucker creado anteriormente como fuente de la distribución

  2. Habilitar acceso restringido al Bucket, Para poder acceder desde la distribución a los archivos privados

  3. Crear un origen de identidad "access-identity-mybucket-ejemplo.s3.amazonaws.com"

  4. Actualizar la politica del Bucket con la Identidad del paso 3, esto permite que se actualize automaticamente, en caso no seleccionar el Paso 4, se debe realizar manualmente.



 Ahora veremos la parte final del formulario de la distribución










Debemos seleccionar "YES" la opción "Restrict Viewer Access"  y creamos la distribución.





Los pasos previos son suficiente para que nuestra distribución de CloudFront espere una URL firmada en cada petición.



Adicionalmente se requiere un CloudFront key par para poder firmar la URL desde el cliente Java, lo puedes obtener en

https://console.aws.amazon.com/iam/home?region=us-east-1#/security_credential



Apunta la clave generada y descarga el archivo .pem





4: Generar una url firmada con el cliente Java de CloudFront



En este paso lo que debemos hacer es crear un proyecto Java con Maven y agregar la siguiente dependencia.








 <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-cloudfront -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-cloudfront</artifactId>
<version>1.9.3</version>
</dependency>




Y el código para firmar nuestra URL desde Java se muestra a continuación.




public class MyTestCloudFrount {
public static void main(String[] args) throws Exception {
/**
* DNS de tu distribución CloudFront
*/
String distributionDomainName = "dnpu4fytk6zvf.cloudfront.net";
/**
* El Private key de CloudFront
*/
File cloudFrontPrivateKeyFile = new File("D:\\pk-APKAJTE3NCSEDSSSD.pem");
/**
* Access Key ID del CloudFront key par
*/
String cloudFrontKeyPairId = "APKAJTE3NCFTGLAPBXRA";
/**
* Nombre del archivo privado que se encuentra en el bucket
* "mybucket-ejemplo"
*/
String fileName = "Crear_bucket.png";
Date expirationDate = new Date(System.currentTimeMillis() + 60 * 1000);
String signedUrl = CloudFrontUrlSigner.getSignedURLWithCannedPolicy(
CloudFrontUrlSigner.Protocol.https,
distributionDomainName,
cloudFrontPrivateKeyFile,
fileName,
cloudFrontKeyPairId,
expirationDate
);
System.out.println(signedUrl);
}
}




Con eso ya podemos acceder a nuestro archivo privado



5: Acceder a nuestro archivo



Sin URL firmado









Con URL Firmado









  Saludos.





29/07/2018

Pentaho Reporting Eventos





Hoy veremos como agregar eventos desde Pentaho Reporting, muy útil para enlazar a otros reportes y pasar parámetros.



En Pentaho Reporting podemos generar a muchos formatos de salida, uno de ellos es HTML, y en este caso HTML nos facilita agregar eventos para poder enlazar  enviando parámetros según nuestras necesidades.





En el vídeo para ver la explicación de la utilización de eventos HTML.













Saludos.



28/07/2018

Jar Ejecutable






En muchos escenarios de desarrollo requerimos implementar  aplicaciones Java empaquetados en un solo .JAR, para poder ejecutar desde comandos y otras tareas según nuestras necesidades.



Una tarea fácil de empaquetar es usando un gestor de dependencias, en este caso Maven,el cual mediante configuración se le indica que como va empaquetar los archivos.



Supongamos que requerimos empaquetar nuestro .jar para obtener información del CPU del servidor, con solo  ejecutar desde un bash se podrá ejecutarlo y sus dependencias también se podrán cargar en memoria.



Lo primero que se debe realizar es localizar el pom.xml del proyecto y agregar la siguiente configuración.








<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.command</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>





El Main Class:<mainClass>com.command</mainClass>



En este bloque de código se debe agregar la clase que se ejecutará por defecto.



Para generar el jar. ejecutar "clean compile assembly:single"



Y listo ya tienen su .jar empaquetado, sin importar la cantidad de dependencias que disponga su aplicación.



Ahora para ejecutar solo basta con ejecutar "java -jar miapp.jar"



Saludos.



16/07/2018

Kettle y Google Spreadsheet





Kettle puede leer datos de una variedad de fuentes, desde base de datos, ficheros, web services, etc.



Hoy comparto como leer desde Google Spreadsheet, es decir podemos editar nuestro Spreadsheet y podremos ver esos cambios en nuestro Dashboard de Pentaho CDE





Para ello tenemos que realizar lo siguiente.



Paso 1:



Habilitar el API de Drive en la consola de Google







Crear una cuenta de servicio con permiso de lectura para recursos, seleccionar que proporcione una nueva clave P12, con esto tendremos nuestra KEY para poder conectarnos desde kettle







Una vez creado nuestra cuenta de servicio podremos ver en nuestra IAM de la consola de Google









Paso 2:



Crear un archivo Google Spredsheet y llenar de datos











Compartir en modo lectura con el correo de la cuenta de servicio creado









Ya tenemos configurado nuestro archivo, ahora solo queda configurar kettle.



Paso 3:



Por defecto kettle no viene instalado el plugin, tendremos que instalar desde el matketplace







Una vez instalado debemos reiniciar y crear una transformación y en la sección Inputs podremos ver el componente para conectarnos  a Google Spreadsheet.



Como primer paso debemos configurar para ello proporcionamos la llave P12, la cuenta de servicio y el ID del Spreadsheet, para obtener el ID del spreadsheet, debemos sacar de la barra de navegación











Probar la conexión y consultar las hojas.



Como resultado podremos ver los datos obtenido desde Google Spreasheet











Espero puedan utilizar Google Spreadsheet en sus procesos de BI como fuente de datos, debido a que los usuarios pueden llenar de datos y fácilmente mostrar los datos en un Dashboard de Pentaho CDE,



Saludos.





Dashboard de métricas





Para monitorear nuestra infraestructura de servidores, una de las herramientas que esta siendo muy activa su uso en la comunidad es Grafana, hoy quiero compartir unas características sobre esta herramienta que actualmente lo uso para mis proyectos.













  • Es una herramienta Open Source

  • Es multilataforma

  • Basado en plugin

  • Dashboard importables

  • Embedible por paneles de gráficos, aunque  aun no permite todo el dashboard

  • Permite conectarse a una multitud de fuentes de datos

  • Interfaz amigable y rápida

  • Soporta varias bases de datos como almacenamiento de configuraciones

  • etc.



Es un proyecto que esta creciendo mucho en la comunidad y muchas empresas lo están utilizando para monitorear su infraestructura.





Otra característica que también  posee es leer datos desde base de datos relacionales, es decir podemos usarlo como herramienta de BI para visualizar nuestros indicadores de negocio.





Pueden acceder a la pagina https://grafana.com/





Aquí pueden ver una colección de ejemplos que la comunidad publica de manera constante. http://play.grafana.org




En mi página de servicios tengo una sección demos donde pueden  ver unas implementaciones  https://explorekpi.com/demos/





Espero que utilicen esta herramienta para sus proyectos, Saludos.






















15/07/2018

Java Zip





En este POST comparto un utilitario para convertir directorios enteros a formato ZIP mediante lineas de comando de forma practica y que se puede ejecutar desde versiones java 7 en adelante.












Lo he implementado para realizar backups de los archivos y configuraciones de los servidores que administro, en linux no fue problema, debido a que hay paquetes que se puede instalar y todo se realiza desde linea de comandos.



El detalle esta en window, para convertir a .zip directorios completos que se ejecutan mediante .bat y con tareas programadas.



Para no instalar herramientas de terceros en windows, he implementado un .jar que permite convertir directorios a .zip y que pueden ser invocados mediante bacheros para propósitos generales.



Utilitario



Java Zip



Requisitos



Java 7+



Instrucciones



Java -jar java-zip.jar "C:\file1\file2" "C:\file3\file2.zip"



Pueden descargar el código fuente en github.  







15/04/2018

Memoria Pentaho BI 2012





Una implementación de pentaho BI con datos universitarios, donde he realizado mis primeros pasos en el ecosistema BI, implementando Saiku Analytics y Saiku AdHoc.



















Saludos


PDR en java web


Para ejecutar un reporte en formato .prpt, se tiene que tener cuidado con las versiones, en este post muestro un ejemplo de ejecutar un reporte implementado con Pentaho Reporting y ejejcutado desde una aplicacion web sin requerir el servidor de pentaho.

Para ello se requiere los siguientes pasos:

  1. Importar las librerias de pentaho Peporting Designer
  2. Ejecutar el archivo .sql que se encuentra en el proyecto adjunto
  3. Realizar las conexiones a la base de datos
  4. Deployar en un servidor web


Las librerias pueden sacarlas desde Pentaho Reporting Designer o bajando desde aqui Libs PDR

Descargar el proyecto con dependencias Maven aqui PentahoMaven

Localizar el archivo reporte1.prpt y abrir con Pentaho Reporting Designer y hacer los cambios que desean.

Importar las librerias al proyecto we y ejecutar.

Teniendo este esquema de implementación facilmente pueden utilizar en las siguientes versiones de Pentaho e integrarlo en sus aplicaciones web

Esta implementación se ha realizado con la version 6.1.0.1-196

Saludos.

14/04/2017

Exportar PNG/JPG Saiku






En las ultimas versiones de saiku analytics, en la versión community, al exportar el gráfico generado por las matrices olap, este genera una marca de agua que muchas veces es incomodo.









Otro aspecto es que ese proceso demora demasiado en el servidor.



Aveces hay errores en la exportación, y nos muestra el típico mensaje de que debes contactar con el administrador.





Para solucionar estos problemas, y ahorrarles a saiku a tener que generar la imagen desde el servidor, lo vamos a generar directamente desde la vista.



Para lograr este propósito debemos hacer uso de la librería.



filesaverj.js



Tiene la facilidad de guardar en varios formatos y desde varios formatos. visitar el link para ver mas opciones.



https://github.com/eligrey/FileSaver.js/



Lo que debemos de hacer es modificar 2 archivos.



 - index.html (biserver-ce/pentaho-solutions/system/saiku/ui)

 - plugin.js (biserver-ce/pentaho-solutions/system/saiku/ui/js/saiku/plugins/CCC_Chart)



El concepto es bien simple.



Saiku cada vez que quieres ver un gráfico distinto y clickeas en el gráfico correspondiente, este carga el gráfico y le pasa los datos, y un div donde va mostrar el svg generado por la librería.



Lo que debemos de hacer es tomar el svg y generar el png o jpg según el tipo seleccionado por el usuario.



Ahora vamos a agregar la librería filesaver.js al index.html






<script type="text/javascript" src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.min.js"></script>








Ahora  agregamos el siguiente método a la clase, justo después en el método exportChart (aunque puede estar en cualquier parte)







download_chart: function (data, x, y, type) {
/** custom **/
var width = x;
var height = y;
var svg = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
var url = URL.createObjectURL(svg);
var img = $('<img />')
.width(width)
.height(height)
.on('load', function () {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img.get(0), 0, 0);
canvas.toBlob(function (blob) {
saveAs(blob, "Grafico de datos." + type);
});
});
img.attr('src', url);
},



Ahora debemos hacer una interrupción a la ejecución del método y enviar al método que acabamos de definir los parámetros necesarios para la conversión debida.





exportChart: function (type) {
var svgContent = new XMLSerializer().serializeToString($('svg')[0]);
var rep = '<svg xmlns="http://www.w3.org/2000/svg" ';
if (svgContent.substr(0, rep.length) != rep) {
svgContent = svgContent.replace('<svg ', rep);
}
this.download_chart(svgContent, $('svg').width(), $('svg').width(), type);
/*
        svgContent = '<!DOCTYPE svg [<!ENTITY nbsp "&#160;">]>' + svgContent;
         var form = $('#svgChartPseudoForm');
         form.find('.type').val(type);
         form.find('.svg').val(svgContent);
         if (this.workspace.query.name != undefined) {
         var f = this.workspace.query.name.substring(this.workspace.query.name.lastIndexOf('/') + 1)

.slice(0, -6);
         form.find('.name').val(f);
         }
         form.attr('action', Settings.REST_URL + this.workspace.query.url() +

escape("/../../export/saiku/chart"));
         form.submit();*/
return false;
},



Con esto ya podemos actualizar y al momento de exportar nuestros gráficos, este debe generarse sin problemas.



Adjunto el vídeo donde se realiza de manera dinámica.









Saludos.


14/11/2016

Manejando Exception






En java las excepciones son muy importante, y si no la usas correctamente, pues no lo estas aprovechando al máximo.









Vamos a trabajar explicitamente sobre la Clase Exception



El uso basicamente depende del escenario y el grado de control que se requiere utilizar.



Para este tutorial vamos a usar nuestra exception que herede de la Clase Exception



Como recomendacion debemos crear una única clase de exepcion para nuestra aplicacion, en este caso crearemos STExeption



Esta clase debe heredar de Exeption como se indica a continuacion



public class STException extends Exception {

private String code;
private int status;

public STException() {
super();
}

/**
     *
     * @param message
     */
public STException(String message) {
super(message);
}

public STException(int status,String message) {
super(message);
this.status=status;
}

/**
     * Este metodo se inicia cuando se invoca desde las excepciones que lo
     * extienden
     *
     * @param status
     * @param code
     * @param message
     */
public STException(int status, String code, String message) {
super(message);
this.status = status;
this.code = code;
}

/**
     *
     * @param status
     * @param message
     * @param rootCause
     */
public STException(int status, String message, Throwable rootCause) {
super(message, rootCause);
this.status = status;
}

/**
     *
     * @param rootCause
     */
public STException(Throwable rootCause) {
super(rootCause);
}

public STException(String message, Throwable rootCause) {
super(message, rootCause);
}

public String getCode() {
return code;
}

public int getStatus() {
return status;
}

}






Como podemos ver la clase tiene 2 atributos Code y Status, estos atributos almacenan los valores que producen las excepciones Hijos, mas adelante veremos que valores y como utilizarlos.





STException debe ser nuestra clase padre de todas nuestras excepciones que queramos controlar. por ejemplo si queremos tener excepciones de validacion, conversion, base de datos, etc.  esta debe implementar de STException. a continuacion veremos 2 excepciones hijas que implementen de STException.





public class AccessDeniedException extends STException {

public static final int status = 401;

public AccessDeniedException() {
super();
}

/**
     *
     * @param message
     */
public AccessDeniedException(String message) {
super(status, message);
}

public AccessDeniedException(String code, String message) {
super(status, code, message);
}

/**
     *
     * @param message
     * @param rootCause
     */
public AccessDeniedException(String message, Throwable rootCause) {
super(status, message, rootCause);
}

/**
     *
     * @param rootCause
     */
public AccessDeniedException(Throwable rootCause) {
super(rootCause);
}
}



En este caso la excepcion es para validar la autenticación, podemos ver que el atributo status tiene un valor por defecto de 401, este codigo se estableció segun: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes



De esta forma cuando lanzamos la excepcion de Autenticación  ya no tendremos que agregar el codigo para respuesta al navegador.





Otro ejemplo de implementacion es:



public class DatabaseException extends STException {

public static final int status = 500;
public DatabaseException() {
super();
}

/**
     *
     * @param message
     */
public DatabaseException(String message) {
super(status,message);
}
public DatabaseException(String code,String message) {
super(status, code, message);
}

/**
     *
     * @param message
     * @param rootCause
     */
public DatabaseException(String message, Throwable rootCause) {
super(status, message, rootCause);
}

/**
     *
     * @param rootCause
     */
public DatabaseException(Throwable rootCause) {
super(rootCause);
}
}



En este caso se estableció un codigo de 500, para indicar que se ha producido un error en el servidor de base de datos o servidor de aplicaciones, los codigo pueden variar segun el grado de precición de la validación.



Ahora veremos como encapsular nuestra excepcion ya sea el tipo que sea todos tiene un solo tipo de salida que es STException.



 @Override
public void remove(String token, int id) throws STException {
log.debug("add ({},{})", token, id);
UserInfo info = null;
try {
info = SessionManager.getInstance().get(token);
TrainingDAO.getInstance().remove(info, id);
} catch (AccessDeniedException e) {
log.error("remove ({},{})", e.getLocalizedMessage(), e);
throw new AccessDeniedException ("Mensaje de objeto autenticacion");
} catch (HibernateException e) {
log.error("remove ({},{})", e.getLocalizedMessage(), e);
throw new DatabaseException("Mensaje de error en la base de dados");
}
log.debug("add void");
}



Compo podemos ver podemos controlar muchas excepciones pero como respuesta daremos como salida solo a STException, por que todas las demas excepciones heredan de esta.



De este modo nos evitamos colocar todas las excepciones en nuestras interfaces y lo simplificamos con una sola.





Ahora supongamos que debemos dar respuesta a la peticion y devolver en el request, solo tendremos que lanzar este control.



    @POST
@Path("/add/{id}")
public ResponseData add(TrainingPartaker item) throws STException {
try {
TrainingPartaker nwitem = STTrainingPartaker.getInstance().add(null, item);
return STMessage.success(nwitem);
} catch (STException e) {
throw new GenericException(e);
} catch (Exception e) {
throw new GenericException(e);
}
}



Ahora si queremos determinar especificamente que excepcion es la que há lanzado nuestra aplicación, solo base de colocarlo de esta forma y sabremos a que excepcion pertenece.



       @POST
@Path("/add/{id}")
public ResponseData add(TrainingPartaker item) throws STException {
try {
TrainingPartaker nwitem = STTrainingPartaker.getInstance().add(null, item);
return STMessage.success(nwitem);
} catch (AccessDeniedException e) {
throw new GenericException(e);
} catch (DatabaseException e) {
throw new GenericException(e);
} catch (ParseException e) {
throw new GenericException(e);
} catch (ConverterException e) {
throw new GenericException(e);
} catch (Exception e) {
throw new GenericException(e);
}
}







Como podemos ver, las excepciones es recomendable encapsularlas al momento de generarlas y desencapsularlas el momento cuando queremos usarlas, o no desencapsularlas si queremos manejar mensajes de proposito general.





Espero que los ayude a manejar mejor sus excepciones en sus aplicacion.








22/02/2016

Anotaciones en Java Reflection



Asi como las clases y palabras reservadas en java, existe un tipo especial para definir  como anotación, es allí donde uno puede crear sus propias anotaciones para usos específicos.











Las anotaciones es una especificación en cual busca simplificar el código usado en java, así mismo junto con Java Reflexion, nos brinda la potencia de poder tener control total de las anotaciones que implementemos.



Las anotaciones son amplia mente utilizadas por la mayorías de frameworks java, por ejemplo Spring Framework con sus @Autowired, Hibernate también hace uso de las anotaciones para simplificar el mapeo de los objetos, evitando escribir en archivos xml.



Vamos a crear nuestra propia anotación y vamos a ver también como podemos usarlo, un caso tipico seria en una validación.



No necesitamos dependencias ya que es una implementan nativa de java.








 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
*
* @author Reynaldo Claros
* @email reyiclaros@gmail.com
*/
@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnotacion {

String mensahe() default "";

}







Esta anotación lo que va hacer es capturar el valor que tiene asignado el campo de la clase que definiremos.



La clase MyClase lo definimos.








 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

/**
*
* @author Reynaldo Claros
* @email reyiclaros@gmail.com
*/
public class MyClase {

@MyAnotacion(mensahe = "Campo name")
private String name;
@MyAnotacion(mensahe = "Campo dni")
private String dni;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDni() {
return dni;
}

public void setDni(String dni) {
this.dni = dni;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}





Después solo tenemos que instanciar la clase asignarle los parámetros y enviarlo a un método para su procesamiento.








 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

public static void main(String[] args) {
MyClase clase = new MyClase();
clase.setName("Java for Developers");
clase.setDni("19283282222");
clase.setAge(2);
/**
* Procesamos
*/
procesandoAnotacion(clase);
}

private static void procesandoAnotacion(Object obj) {
Class cl = obj.getClass();
try {
for (Field field : cl.getDeclaredFields()) {
field.setAccessible(true);
try {
for (Annotation anno : field.getDeclaredAnnotations()) {
if (anno.annotationType() == MyAnotacion.class) {
MyAnotacion myanotacion = (MyAnotacion) anno;
System.out.println("Mensaje de la anotacion : " + myanotacion.mensahe());
System.out.println("Nombre del campo : " + field.getName());
System.out.println("Valor del campo : " + field.get(obj).toString());
System.out.println("----------------------------");
}
}
} catch (IllegalAccessException | IllegalArgumentException | SecurityException e) {
System.out.println(e.getMessage());
}
}
} catch (SecurityException | IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}





El resultado es:








1
2
3
4
5
6
7
8

Mensaje de la anotacion : Campo name
Nombre del campo : name
Valor del campo : Java for Developers
----------------------------
Mensaje de la anotacion : Campo dni
Nombre del campo : dni
Valor del campo : 19283282222
----------------------------







Como podéis ver, las anotaciones son una poderosa herramienta, cuando queremos hacer nuestros propios validadores y otros cometidos.



Saludos cordiales.