lunes, 10 de diciembre de 2018

AEM hablemos del arquetipo 11

Cuando creamos un proyecto con AEM. Siempre es importante saber que arquetipo estamos usando. Pues esto me determinara que source, herramientas y auto-configuraciones se esta utilizando.


Para declarar un servlet;

 Arquetipo 10:


@SlingServlet(paths="/bin/mySearchServlet", methods = "POST", metatype=true)
public class HandleClaim extends org.apache.sling.api.servlets.SlingAllMethodsServlet {
    private static final long serialVersionUID = 2598426539166789515L;
}


Arquetipo 11:

@Component(service=Servlet.class,
property={
Constants.SERVICE_DESCRIPTION + "=Simple Demo Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_POST,
"sling.servlet.paths="+ "/bin/myDataSourcePoolServlet"
})
}



Para usar @reference;

 Arquetipo 10:

import org.apache.felix.scr.annotations.Reference;

@Reference
private DataSourcePool dataPool;


Arquetipo 11:

import org.osgi.service.component.annotations.Reference;

@Reference
private DataSourcePool dataPool;


Usando DataPools:


Arquetipo 10:
Se configura como; Apache Sling Connection Pooled DataSource
http://localhost:4502/system/console/configMgr


Arquetipo 11:

Se configura como; Day Commons JDBC Connections Pool
http://localhost:4502/system/console/configMgr

miércoles, 5 de diciembre de 2018

Adobe AEM Form + AEM Data Model + MySql Example

Prerequisitos:

  1. AEM 6.3
  2. AEM-6.3.3.0-6.3.3.zip
  3. AEM-CFP-6.3.3.1-1.0.zip
  4. AEM-FORMS-6.3.3.1-LX-4.1.90.zip
  5. Mysql 

Pasos:

Necesitamos crear un ambiente con todos los prerequisitos anteriormente listados. 



Seguidamente necesitamos crear una base de datos.

Script:

CREATE DATABASE Registro_de_mascotas;
USE Registro_de_mascotas;

CREATE TABLE Mascotas (Nombre VARCHAR(20), Raza VARCHAR(30), Sexo CHAR(1), Fecha_de_nacimiento DATE);


Debemos crear la conexión a la base de datos. Y lo para esto, necesitamos;

Instalar los drivers en AEM:
Lo hacemos atravez de este tool:

http://localhost:4502/system/console/bundles

Dentro instalamos los bundles que necesitemos. Para este caso en especifico instalamos el de Mysql.


Este lo podes descargar aqui





Configurar Mysql como Datasource de AEM

Esto lo hacemos en el siguente tool:
http://localhost:4502/system/console/configMgr

Dentro buscamos: Apache Sling Connection Pooled DataSource

Y pulsamos en mas (+)

En el formulario, ponemos los datos de la base de datos:

Detalles:
Notas: Los datos que no se encuentra debajo dejarlos default


Datasource name: MascotasDataSource
DataSource service property name:
datasource.name
JDBC driver class:
com.mysql.jdbc.Driver
JDBC connection URI:
jdbc:mysql://localhost:3306/Registro_de_mascotas?autoReconnect=true&useUnicode=true&characterEncoding=utf-8
Username:
root
Password:
<VACIO>
Test on Borrow:
True
Test on Return:
True
Validation Query:
-1
Transaction Isolation:
READ_COMMITTED

Después de pulsar Save. Se creara por debajo un nuevo data source:



Nuestro siguiente paso es crear un nuevo data model.
http://localhost:4502/aem/forms.html/content/dam/formsanddocuments-fdm




Agregamos un nombre y pulsamos siguiente;



Seleccionamos el Datasource







Y pulsamos el botón de crear
Tenemos que editar el DataModel Recién creado.




Dentro en el Panel de edición, simplemente podemos desplegar el árbol y tendremos acceso a la base de datos.

Debemos agregar la tabla y los inputs.  Dentro del modelo:


Pulsamos el botón "Add Selected". Se agregara una tabla al panel de edición:

 Tenemos que editar la tabla y escogerles los modos y servicios (Mas adelante se explica esto en detalle)



Debemos escoger el;
Read Service: get.
Bidding To: Request Atribute
Biding Value: Nombre. (Nombre de la tabla)
Es importante destacar que he tenido problemas configurando el Bidding Value. Si se presenta ese problema utilizar la nomenclatura <Nombre Tabla>.<Nombre campo> eg; Mascotas.Nombre

Debemos escoger el;
Write Service: insert






Pulsamos Done.
Ahora nos toca configurar los servicios.

Editamos el servicio Get:




 Escogemos el método;
Output Model Object: Mascotas.
Return array?: True (Por que la tabla de prueba no tiene llave primaria)

Editamos el servicio Insert:

Escojemos:
Output Type: Boolean (Defecto)
Arguments: Mascotas







Nuestra siguiente tarea seria probar que el DataModel este funcionando correctamente.

Entramos al utilitario de Test Model Object


Dentro escogemos el
Select Model/Service: Write model Object

Y debemos escribir los datos a insertar:

{
  "Mascotas": {
    "Nombre": "Pepe",
    "Raza": "Indefinida",
    "Sexo": "M",
    "Fecha_de_nacimiento": "2015-12-17"
  }  
}


Y pulsamos el botón Test:

Mi experiencia me dice que este tool tiene mucho problemas, pues me a tocado pulsar repetidamente Test, hasta 5 veces para la respuesta del insert sea True.

Ahora nos toca pulsar la búsqueda.

En este caso escogemos:
Select Model/Service: Read model object

Pulsamos Mascotas. Y nos generara un template solicitando el Nombre.
Seria poner "Gabo" para hacer referencia al que acabamos de insertar.


{
    "request": {
        "attribute": {
            "Nombre": "Gabo"
        }
    }
}


De igual manera que en el insert, Me toco pulsar varias veces el botón de Test. Porque las primeras veces me muestra errores de conexión, como el 4 o 5 intento funciona correctamente.

Crear el formulario:

El paso final es crear el formulario basado en el Data Model anterior, en el siguiente tool:


http://localhost:4502/aem/forms.html/content/dam/formsanddocuments


Creamos un Adaptive Form



Creamos un Template en blanco
Nombramos el Formulario como: MascotasForm





Escogemos el datasource


Y pulsamos el botón Create.

Seguidamente tenemos que editar el formulario:
Nos vamos al tab de Data Model Objects y arrastramos toda la tabla:


Luego agregamos el botón de submit:







Y editamos el container del formulario:
En la sección de  Submission:
Submit Action: Submit using Form Data model
Data Model to submit: Escojemos el del mascotas.

Y por ultimo guardamos los cambios.

Ahora solo resta pulsar el botón de preview.
De igual manera que los tool de testing, cuando doy submit la primera vez me genera un error. Es hasta el segundo submit cuando efectivamente se insertan los valores en la base de datos.

martes, 20 de noviembre de 2018

Clonando y cambiando partición root en Linux

Contexto:
Sucede que mis particiones de root siempre las hago alrededor de los 20GB. Usualmente esto me da espacio suficiente para soportar mucho tiempo antes de la próxima reinstalación.
 Pero esta vez no, cuando trate de dimensionar root, me dio errores. Entonces tome la decisión de clonar root y cambiarlo.

Nota:
De momento ha funcionado bien y sin problemas.

Pasos:
  1. Utilizando un Live CD en mi caso use Kubuntu 14.02 (Viejo). Entro en en modo "Probar sin instalar".
  2.  Dentro entro al gestor de particiones de KDE. Comando:
    partitionmanager




  • Dentro encontré: 

    • /dev/sda7 como root (20GB), 
    • /dev/sda5 como home(350GB). 
    • Simplemente lo que hice fue hacer algo de espacio para la nueva partición que superara su tamaño original. Esta fue asignada con 90GB y quedo como /dev/sda8




  • Lo siguiente que debemos hacer es clonar sda7 (Viejo root) en /dev/sda8 (Nuevo root). Usando el comando: 
    dd if=/dev/sda7 of=/dev/sdb8 bs=64K conv=noerror,sync
  •  El siguiente paso fue montar /dev/sda7 y el /dev/sda8 para poder editar el fstab. Usando Dolphin es solo cuestión de darle un par de clicks.
  •  Debemos editar el /etc/fstab de ambas particiones. Quedaría algo como esto: Nota: Soy de vieja escuela y siempre me ha parecido mejor usar particiones que UUID. Sin embargo en el final de este post encontraras como cambiar los UUID de la vieja partición.
  • Como se logra ver en la imagen anterior, antes se usaba la UUID del /dev/sda7. Pero ahora directamente lo cambie para /dev/sda8. Y esto para no tener que lidear con NADA mas. Sino tendriamos que actualizar un monton de cosas entre ellas grub.(Recortar cambiar el FSTAB DE AMBAS PARTICIONES)
  • Para este punto ya podemos reiniciar (Dejar de usar el LiveCD
  • Con la nueva partición corriendo, si ejecutamos el
    df -h
    se puede notar  que la partición aun tiene 20Gb de espacio. Esto es porque se clono de forma que la tabla de particiones se duplico. Lo que debemos hacer es ejecutar este comando:
    sudo resize2fs /dev/sda8 
    de esta forma se actualiza y ahora si me marca los 90GB de espacio. 

  • Epilogo
    Como editar el UUID de un disco duro con comandos?

    Contexto:
    Como se duplico la vieja root, también duplico el UUID y esto no es recomendable.

    Es tan sencillo como generar un nuevo UUID y actualizarlo:

    uuidgen
    #bbef6868-6903-456e-ad5e-2784154dfb9a
    tune2fs /dev/sda7 -U bbef6868-6903-456e-ad5e-2784154dfb9a
    

    domingo, 11 de marzo de 2018

    Jugando con las macros del Razer BlackWidow Ultimate 2012 para Linux(Parte 1)

    Nota: Ya existen proyectos super eficientes como OpenRazer.

    Sin embargo el presente articulo fue creado con el fin de experimentar un poco con libusb, udev.

    Para quien es este articulo?
    Esta pensando para programadores, y curiosos. No se explica como funciona Libusb, pero se da un ejemplo de vida real.

    Contexto:
    El teclado viene con 5 Macro Keys. Que necesitan ser inicial izadas en orden de que Linux detecte sus entradas. Desgraciadamente para ello se necesita, hacer un poco de ingeniería inversa de las entradas. El objetivo de  articulo no es para aprender a hacer ingeniería inversa del tema. Pero pueden ver un vídeo muy ilustrativo aqui.

    En resumen; Lo que necesitamos hacer es mandar unos bits mágicos a través de LibUSB al teclado para que empiece a usar los Macros.
    La forma mas sencilla de probar todo es con evtest.

    sudo evtest
    No device specified, trying to scan all of /dev/input/event*
    Available devices:
    #Blablabla en mi compu el input esta en el 4
    /dev/input/event4:      Razer Razer BlackWidow Ultimate
    /dev/input/event5:      Razer Razer BlackWidow Ultimate
    /dev/input/event6:      Razer Razer BlackWidow Ultimate
    #Blablabla
    Select the device event number [0-20]: 4
    Input driver version is 1.0.1
    Input device ID: bus 0x3 vendor 0x1532 product 0x10d version 0x111
    Input device name: "Razer Razer BlackWidow Ultimate"
    Supported events:
      Event type 0 (EV_SYN)
        #Bla bla bla Y esta es la parte interesante... Note que el Key configura teclas F13 en adelante. Esas son las macros.
        Event code 183 (KEY_F13)
        Event code 184 (KEY_F14)
        Event code 185 (KEY_F15)
        Event code 186 (KEY_F16)
        Event code 187 (KEY_F17)
        Event code 188 (KEY_F18)
        Event code 189 (KEY_F19)
        Event code 190 (KEY_F20)
        Event code 191 (KEY_F21)
        Event code 192 (KEY_F22)
        Event code 193 (KEY_F23)
        Event code 194 (KEY_F24)
        Event code 240 (KEY_UNKNOWN)
      Event type 4 (EV_MSC)
        Event code 4 (MSC_SCAN)
      Event type 17 (EV_LED)
        Event code 0 (LED_NUML)
        Event code 1 (LED_CAPSL)
        Event code 2 (LED_SCROLLL)
    Key repeat handling:
      Repeat type 20 (EV_REP)
        Repeat code 0 (REP_DELAY)
          Value    250
        Repeat code 1 (REP_PERIOD)
          Value     33
    Properties:
    Testing ... (interrupt to exit)
    Event: time 1520787420.323002, type 17 (EV_LED), code 0 (LED_NUML), value 0
    Event: time 1520787420.323002, -------------- EV_SYN ------------
    Event: time 1520787420.376467, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028
    Event: time 1520787420.376467, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
    Event: time 1520787420.376467, -------------- EV_SYN ------------
    Event: time 1520787422.226497, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e0
    Event: time 1520787422.226497, type 1 (EV_KEY), code 29 (KEY_LEFTCTRL), value 1
    Event: time 1520787422.226497, -------------- EV_SYN ------------
    Event: time 1520787422.476487, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006
    Event: time 1520787422.476487, type 1 (EV_KEY), code 46 (KEY_C), value 1
    Event: time 1520787422.476487, -------------- EV_SYN ------------


    Cada vez que toquen una tecla convencional, verán el input de la tecla. Pero si se presiona alguna de las macros no pasa nada. Para solucionar cree un pequeño programa en C el cual le pasa los bits mágicos al teclado.

    #include 
    #include 
    #include 
     
    using namespace std;
     
    #define VENDOR_ID 0x1532
    #define PRODUCT_ID 0x10D
    #define USB_REQUEST_TYPE  0x21
    #define USB_VALUE  0x300
    #define USB_REQUEST  9
    #define USB_INDEX  0
    #define USB_INTERFACE  0 //La interfaz de configuracion esta en el 0
     
    unsigned char buffer[90] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00}; //Magic bits
     
    int main(int argc, char** argv) {
        libusb_context *ctx = NULL; //a libusb session
        libusb_device_handle *dev_handle; //a device handle
        int result; //Result form the writting
        result = libusb_init(&ctx); //initialize a library session
        if (result < 0) {
            cout << "libusb_init init error " << result << endl; //there was an error
            return false;
        }
        dev_handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID); //these are vendorID and productID I found for my usb device
        if (dev_handle == NULL) {
            cout << "libusb_open_device_with_vid_pid cannot open Blackwidow keyboard" << endl;
            return false;
        }
        if (libusb_kernel_driver_active(dev_handle, USB_INTERFACE) == 1) {
            if (libusb_detach_kernel_driver(dev_handle, USB_INTERFACE) != 0) {
                cout << "libusb_detach_kernel_driver error" << endl;
                return false;
            }
        }
        result = libusb_claim_interface(dev_handle, USB_INTERFACE); //claim interface 0 (the first) of device (mine had jsut 1)
        if (result < 0) {
            cout << "Cannot Claim Interface" << endl;
            return false;
        }
        result = libusb_control_transfer(dev_handle, USB_REQUEST_TYPE, USB_REQUEST, USB_VALUE, USB_INDEX, buffer, 90, 0);
        if (result != 90) {
            return false;
        }
        result = libusb_release_interface(dev_handle, USB_INTERFACE); //release the claimed interface
        if (result != 0) {
            cout << "Cannot Release Interface" << endl;
            return false;
        }
        //Attached and reclain the driver
        libusb_attach_kernel_driver(dev_handle, USB_INTERFACE);
        libusb_close(dev_handle); //close the device we opened
        libusb_exit(ctx); //needs to be called to end the
        return 0;
    }
    


    Ahora bien debemos compilar el programa con libusb y ejecutar este programa con sudo

    # Instalar la libreria necesaria
    sudo apt-get install libusb-1.0-0-dev
    # Instalar GCC
    sudo apt-get install build-essential
    # Compilar
    g++ blackwidowkeyboardinit.cpp `pkg-config libusb-1.0 --libs --cflags` -o blackwidowkeyboardinit
    
    # Ejecutar el programa
    sudo ./blackwidowkeyboardinit 
    
    #Ahora bien debemos moverlo a una ubicacion final
    sudo mv blackwidowkeyboardinit /usr/bin/blackwidowkeyboardinit
    

    Y por ultimo volvemos a probar con evtest.

    Ahora si veremos las entradas del teclado cuando presionemos algún MacroKey...

    Lo que queda es que el programa se ejecute con permisos de super usuario, cuando se inserta el teclado. Para eso recurrimos al udev.
    #Dentro de la carpeta /etc/udev/rules.d
    #Creamos un archivo 
    sudo touch 40-razer_blackwidow_keyboard.rules
    
    #Con el contenido
    #ACTION=="add", ATTR{idVendor}=="1532", ATTR{idProduct}=="010d", RUN+="/bin/sh -c 'echo == >> /home/koza/udev-env.txt; env >> /home/koza/udev-env.txt'"
    #ACTION=="add", ATTR{idVendor}=="1532", ATTR{idProduct}=="010d", RUN+="/usr/bin/blackwidowkeyboardinit"
    
    #Refrescamos las reglas con udev
    sudo udevadm control --reload-rules
    
    #Reiniciasmos udev
    sudo service udev restart
    

    Tomar en cuenta que la primera linea del archivo se puede eliminar, Pero por testing la dejo allí.
    Simplemente cuando insertar el teclado en un USB en home crear un archivo con los datos del ambiente.

    Si quieres experimentar con las reglas debes simplemente ejecutar el comando siguiente después de cada cambio.

    udevadm control --reload-rules && udevadm trigger
    


    Nota: Probado en Debian 8 (Jessie)

    sábado, 2 de septiembre de 2017

    Configurar Android Devices para desarrollo en Linux (Debian 8)

    Es muy comun encontrarse este error despues de ejecutar:

    adb devices
    
    #Error al mostrar que no hay permisos:
    List of devices attached
    M4 SS1070       no permissions (verify udev rules); see [http://developer.android.com/tools/device.html]

    Aquí el problema es que los usb son mas restrictivos en linux.
    Pero no te alarmes. Es sencillo de resolver.

    Lo que voy a mostrar en una recopilación de la mayoría de vendors para que no sufras mas por esto. Eventualmente si después de seguir los pasos abajo mostrados aun te sigue saliendo.
    Tendrás que buscar el vendo-Id correcto para tu device.

    #Edita/Agregar el archivo de udev rules
    sudo nano /etc/udev/rules.d/51-android.rules
    
    #Agregar la lista de abajo al archivo.#51-android.rules: 
    #Lista con los vendors mas comunes
    SUBSYSTEM=="usb", ATTR{idVendor}=="0502", MODE="0666", GROUP="plugdev" #Acer
    SUBSYSTEM=="usb", ATTR{idVendor}=="0b05", MODE="0666", GROUP="plugdev" #ASUS
    SUBSYSTEM=="usb", ATTR{idVendor}=="413c", MODE="0666", GROUP="plugdev" #Dell
    SUBSYSTEM=="usb", ATTR{idVendor}=="0489", MODE="0666", GROUP="plugdev" #Foxconn
    SUBSYSTEM=="usb", ATTR{idVendor}=="04c5", MODE="0666", GROUP="plugdev" #Fujitsu
    SUBSYSTEM=="usb", ATTR{idVendor}=="04c5", MODE="0666", GROUP="plugdev" #Fujitsu Toshiba
    SUBSYSTEM=="usb", ATTR{idVendor}=="091e", MODE="0666", GROUP="plugdev" #Garmin-Asus
    SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev" #Google
    SUBSYSTEM=="usb", ATTR{idVendor}=="201E", MODE="0666", GROUP="plugdev" #Haier
    SUBSYSTEM=="usb", ATTR{idVendor}=="109b", MODE="0666", GROUP="plugdev" #Hisense
    SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev" #HTC
    SUBSYSTEM=="usb", ATTR{idVendor}=="12d1", MODE="0666", GROUP="plugdev" #Huawei
    SUBSYSTEM=="usb", ATTR{idVendor}=="24e3", MODE="0666", GROUP="plugdev" #K-Touch
    SUBSYSTEM=="usb", ATTR{idVendor}=="2116", MODE="0666", GROUP="plugdev" #KT Tech
    SUBSYSTEM=="usb", ATTR{idVendor}=="0482", MODE="0666", GROUP="plugdev" #Kyocera
    SUBSYSTEM=="usb", ATTR{idVendor}=="17ef", MODE="0666", GROUP="plugdev" #Lenovo
    SUBSYSTEM=="usb", ATTR{idVendor}=="1004", MODE="0666", GROUP="plugdev" #LG
    SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", MODE="0666", GROUP="plugdev" #Motorola
    SUBSYSTEM=="usb", ATTR{idVendor}=="0e8d", MODE="0666", GROUP="plugdev" #MTK
    SUBSYSTEM=="usb", ATTR{idVendor}=="0409", MODE="0666", GROUP="plugdev" #NEC
    SUBSYSTEM=="usb", ATTR{idVendor}=="2080", MODE="0666", GROUP="plugdev" #Nook
    SUBSYSTEM=="usb", ATTR{idVendor}=="0955", MODE="0666", GROUP="plugdev" #Nvidia
    SUBSYSTEM=="usb", ATTR{idVendor}=="2257", MODE="0666", GROUP="plugdev" #OTGV
    SUBSYSTEM=="usb", ATTR{idVendor}=="10a9", MODE="0666", GROUP="plugdev" #Pantech
    SUBSYSTEM=="usb", ATTR{idVendor}=="1d4d", MODE="0666", GROUP="plugdev" #Pegatron
    SUBSYSTEM=="usb", ATTR{idVendor}=="0471", MODE="0666", GROUP="plugdev" #Philips
    SUBSYSTEM=="usb", ATTR{idVendor}=="04da", MODE="0666", GROUP="plugdev" #PMC-Sierra
    SUBSYSTEM=="usb", ATTR{idVendor}=="05c6", MODE="0666", GROUP="plugdev" #Qualcomm
    SUBSYSTEM=="usb", ATTR{idVendor}=="1f53", MODE="0666", GROUP="plugdev" #SK Telesys
    SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="plugdev" #Samsung
    SUBSYSTEM=="usb", ATTR{idVendor}=="04dd", MODE="0666", GROUP="plugdev" #Sharp
    SUBSYSTEM=="usb", ATTR{idVendor}=="054c", MODE="0666", GROUP="plugdev" #Sony
    SUBSYSTEM=="usb", ATTR{idVendor}=="0fce", MODE="0666", GROUP="plugdev" #Sony Ericsson
    SUBSYSTEM=="usb", ATTR{idVendor}=="2340", MODE="0666", GROUP="plugdev" #Teleepoch
    SUBSYSTEM=="usb", ATTR{idVendor}=="0930", MODE="0666", GROUP="plugdev" #Toshiba
    SUBSYSTEM=="usb", ATTR{idVendor}=="19d2", MODE="0666", GROUP="plugdev" #ZTE
    SUBSYSTEM=="usb", ATTR{idVendor}=="0414", MODE="0666", GROUP="plugdev" #Gigabyte
    
    #Ejecutar el comando:
    sudo udevadm control --reload-rules
    #Esto con el objetivo de no reiniciar tu PC
    #Y refrescar los Udev en "caliente"
    
    
    #Por ultimo simplemente volver a conectar nuestro device a la computadora y ejecutar
    adb devices
    
    List of devices attached
    M4 SS1070       device



    martes, 18 de julio de 2017

    miércoles, 1 de marzo de 2017

    Seguridad con SpringBoot y CSRF

    La seguridad con con Springboot es realmente sencilla.
    Para activar la Basic Html, simplemente creamos un conjunto de clases de esta forma:

    @EnableWebSecurity
    @Configuration
    @EnableSpringHttpSession
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Value("${com.pmj.dyo.configuration.security.user}")
        private String user;
    
        @Value("${com.pmj.dyo.configuration.security.password}")
        private String password;
        
        @Value("${com.pmj.dyo.configuration.csrf.login}")
        private String loginPage;
        
        @Value("${com.pmj.dyo.configuration.csrf.allow}")
        private String[] patterns;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers(patterns).permitAll().and().csrf().disable().httpBasic().and()
                    .addFilterAfter(csrfFilter(patterns), FilterSecurityInterceptor.class)
                    .addFilterAfter(new CsrfGrantingFilter(loginPage), CsrfFilter.class);
        }
    
        private Filter csrfFilter(String[] patterns) {
            CsrfFilter csrfFilter = new CsrfFilter(csrfTokenRepository());
            csrfFilter.setRequireCsrfProtectionMatcher(csrfProtectionMatcher(patterns));
            return csrfFilter;
        }
    
        private NoAntPathRequestMatcher csrfProtectionMatcher(String[] patterns) {
            return new NoAntPathRequestMatcher(patterns);
        }
    
        private CsrfTokenRepository csrfTokenRepository() {
            HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
            repository.setHeaderName(X_XSRF_TOKEN);
            return repository;
        }
    
        /**
         * bCryptPasswordEncoder
         * 
         * @return
         */
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        /**
         * configureGlobal
         * 
         * @param auth
         * @throws Exception
         */
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication().withUser(user).password(password).roles("USER");
        }
    
        /**
         * sessionRepository
         * 
         * @return
         */
        @Bean
        @SuppressWarnings("rawtypes")
        public SessionRepository sessionRepository() {
            return new MapSessionRepository();
        }
    
        /**
         * sessionStrategy
         * 
         * @return
         */
        @Bean
        public HeaderHttpSessionStrategy sessionStrategy() {
            return new HeaderHttpSessionStrategy();
        }
    
        /**
         * @return the user
         */
        public String getUser() {
            return user;
        }
    
        /**
         * @param user
         *            the user to set
         */
        public void setUser(String user) {
            this.user = user;
        }
    
        /**
         * @return the password
         */
        public String getPassword() {
            return password;
        }
    
        /**
         * @param password
         *            the password to set
         */
        public void setPassword(String password) {
            this.password = password;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////
    
    
    public class CsrfGrantingFilter implements Filter {
    
        public static final String X_XSRF_TOKEN = "X-XSRF-TOKEN";
    
        private String loginPage;
    
        private final Logger log = LoggerFactory.getLogger(this.getClass());
    
        /**
         * Login Page injection
         * @param loginPage
         */
        public CsrfGrantingFilter(String loginPage) {
            this.loginPage = loginPage;
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            CsrfToken csrf = (CsrfToken) servletRequest.getAttribute(CsrfToken.class.getName());
            String token = csrf.getToken();
            if (token != null && isAuthenticating(servletRequest)) {
                servletRequest.setAttribute(X_XSRF_TOKEN, true);
            } else {
                servletRequest.setAttribute(X_XSRF_TOKEN, false);
            }
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        private boolean isAuthenticating(ServletRequest servletRequest) {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            return request.getRequestURI().equals(loginPage);
        }
    
        @Override
        public void destroy() {
            LogUtil.info(log, this.toString());
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            LogUtil.info(log, filterConfig.toString());
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    @RequestMapping(method = POST, path = "", produces = APPLICATION_JSON_VALUE)
        public Map login(@RequestBody UserEntry userEntry, ServletRequest servletRequest,
                ServletResponse servletResponse) {
            boolean xsrfAvailable = (boolean) servletRequest.getAttribute(X_XSRF_TOKEN);
            Authorization aut = client.login(userEntry);
            Map resolve = new HashMap(); 
            if (aut != null && aut.isAccepted() && xsrfAvailable) {
                CsrfToken csrf = (CsrfToken) servletRequest.getAttribute(CsrfToken.class.getName());
                String token = csrf.getToken();
                HttpServletResponse response = (HttpServletResponse) servletResponse;
                Cookie cookie = new Cookie(X_XSRF_TOKEN, token);
                cookie.setPath("/");
                cookie.setSecure(true);
                response.addCookie(cookie);
                resolve.put(STATUS, AUTHORIZED);
                resolve.put(USERNAME, username);
                resolve.put(PASSWORD, password);
                resolve.put(ROLE, aut.getRole());
                resolve.put(TOKEN, token);
            } else {
                resolve.put(STATUS, UNAUTHORIZED);
            }
            return resolve;
        }
    


    Básicamente lo que sucede en este ejemplo es lo siguiente:
    1.  El punto de control que genera el Cross Site Request Forgery es /login
    2. Si el login no es efectivo el CSRF no aparece como set en el cookie
    3. Ahora bien el toque esta en que el body también presenta el basic autentification y el CSRF. De esta forma es mas sencillo que el Javascript almacene los datos.
    4. Cada nuevo request debe enviar los Basic Login y el CSRF.
    Dentro de la aplicacion pasa esto:
    1.  La aplicacion fija el toking en el login. 
    2. Si cualquier otro request que no este en la lista de permitidos es invocada. Revisa el Basic Aut y el CSRF toking. La clase que genera los toking es CsrfGrantingFilter.

    martes, 21 de febrero de 2017

    Java Poi con Maven y Springboot Restful (Usando imagenes)

    Este articulo no es un "tutorial". Es un conjunto de notas de mi experiencia.
    Si vas a adentrarte en este articulo. Debes conocer como usar POI. Maven y Springboot Restfull.

     Lo primero que debemos hacer es configurar el POM del maven para usar  todas las características de excel. Claramente algunas no son necesarias. Pero es mejor tenerlas para usar TODO lo que Excel ofrece:

    
          dom4j
          dom4j
          1.6.1
      
      
       org.apache.poi
       poi
       3.9
      
      
       org.apache.poi
       poi-ooxml
       3.9
      
      
          org.apache.commons
          commons-collections4
          4.1
      
      
          org.apache.xmlbeans
          xmlbeans
          2.3.0
      
    

    Ahora bien para generar reportes POI ofrece varias características principalmente varias vistas de distintos tipos. Para no complicarse vamos a usar lo que SpringBoot ofrece.


    No es recomendable... generar los reportes como stream dentro de los HttpServletResponse . Porque se puede cortar el request y el reporte quedar corrupto. Usar siempre las vistas.

    //Lo primero debemos escojer un view que se ajuste a las necesidades. Al final hablare de los distintos tipos
    public class ExcelBuilder extends AbstractXssfStreamingView {
    
        @Override
        public void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
            //Aqui ya vienen inicializado el workbook.
            //La unica funcion es implementar. Seria; Crear el sheet, crear filas, celdas, poner estilos, etc
            //No debemos preocuparnos por escribir el workbook en el response. Solo dejemos que el metodo termine.
            //Y Spring sabe que debe tomar el workbook y generar un archivo.
        }
    
    }
    
    //Debemos configurar que la vista sea usada para los endpoint
    //Sencillamente podemos usar esto:
    @Configuration
    public class ExcelBuilderConfig {
        
        @Bean
        public ExcelBuilder ExcelBuilder() {
            return new ExcelBuilder();
        }
    
    }
    
    //Ahora bien solo resta usarlo en algun endpoint
    @Api(value = "contest", description = "the contest API")
    public interface ContestApi {
    
        /**
         * contestApplicantExport
         *
         * @param contest
         * @param brandid
         * @return
         */
        @ApiOperation(value = "", notes = "Returns a excel file report according to the information provided (A5:ContestApplicantExport)")
        @ApiResponses(value = {@ApiResponse(code = 200, message = "gallery response"),
                @ApiResponse(code = 200, message = "unexpected error")})
        @RequestMapping(value = "/contest/{contest}/{brandid}", produces = {
                "application/ms-excel"}, method = RequestMethod.GET)
        @org.springframework.web.bind.annotation.GetMapping("/dyo-config")
        ModelAndView contestApplicantExport(
                @ApiParam(value = "Filter based on a specific contest", required = true) @PathVariable("contest") String contest,
                @ApiParam(value = "Filter based on a specific brand", required = true) @PathVariable("brandid") String brandid,
                @ApiParam(value = "HttpServletResponse to setup the excel ouput", required = true) HttpServletResponse response);
    }
    
    
    
    @Configuration
    @RestController
    public class ContestApiController implements ContestApi {
    
    
        @Override
        public ModelAndView contestApplicantExport(
                @ApiParam(value = "Filter based on a specific contest", required = true) @PathVariable("contest") String contest,
                @ApiParam(value = "Filter based on a specific brand", required = true) @PathVariable("brandid") String brandid,
                @ApiParam(value = "HttpServletResponse to setup the excel ouput", required = true) HttpServletResponse response) {
    
            Book book = /*Cualquier Objecto*/
            return new ModelAndView("ExcelBuilder", "book", book); //Note que "book" es el dato que se puede obtener de la vista
        }
    }
    
    
    Los diferentes tipos de vistas presentes generan diferentes tipos de workbook.
    Cada una con características diferentes:
    Podemos mencionar XSSFWorkbook and SXSSFWorkbook.

    La clase AbstractXssfStreamingViewes funcional para archivos muy grandes. Sin embargo tiene la tendencia a no funcionar de buena manera con las imágenes. Puede que te tengas que enfrentar a Streaching o a resize ridículos. Después de muchos intentos y de canas verdes. Descubrí que si uno quiere insertar imágenes. La mejor forma es usando XSSFWorkbook.

    Para eso escribí mi propia versión de un AbstractXlsxView.

    //Simplemente hacemos esto:
    public abstract class AbstractXssfStreamingView extends AbstractXlsxView {
    
        @Override
        protected XSSFWorkbook createWorkbook(Map model, HttpServletRequest request) {
            return new XSSFWorkbook();
        }
    
    }
    
    //Y lo utilizamos:
    public class ExcelBuilder extends AbstractXssfStreamingView {
    
        @Override
        public void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
            Book book = (Book) model.get("book"); //Usar de referencia al ejemplo de arriba para obtener los datmos del model
            //Tu codigo aqui
        }
    
    }
    
    //En el codigo de ejemplo para agregar imagenes creo un pequeno factory.
    //La implementacion es por un conjunto de intefacez de esta manera:
    
    @FunctionalInterface
    public interface CellProduceInterface {
    
        /**
         * update
         * 
         * @param excelCell
         * @param data
         * @param workbook
         * @param sheet
         * @param point
         */
        public void update(org.apache.poi.ss.usermodel.Cell excelCell, Cell data, Workbook workbook, Sheet sheet, Point point);
    
    }
    
    //Y su implementacion
    //Notas:
    //El excelCell es el cell de POI
    //El data es el modelo de la informacion de la celda
    //Woorkbook asociado con la vista 
    //Sheet actual en que que excelCell esta presente
    public class ImageCellProduce implements CellProduceInterface {
    
        private static final Logger log = LoggerFactory.getLogger(ImageCellProduce.class);
    
        @Override
        public void update(org.apache.poi.ss.usermodel.Cell excelCell, Cell data, Workbook workbook, Sheet sheet,
                Point point) {
            String path = (String) data.getValue();
            if (path != null) {
                byte[] bytes = ExcelUtil.convertImagePathToBytes(path);
                if (bytes.length > 0) {
                    int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
                    CreationHelper helper = workbook.getCreationHelper();
                    Drawing drawing = sheet.createDrawingPatriarch();
                    ClientAnchor anchor = helper.createClientAnchor();
                    //Col and Cell pos
                    anchor.setCol1(point.y);
                    anchor.setRow1(point.x);
                    //Height is not possible without stretched the image
                    Picture pict = drawing.createPicture(anchor, pictureIdx);
                    if (data.getWidth() != -1) {
                        sheet.setColumnWidth(point.y, ExcelUtil.calculatePoiWidthSize(data.getWidth()));
                        data.setWidth(-1);//Asi no se vuelve a aplicar el estilo mas adelante
                    }
                    if (data.getHeight() != -1) {
                        excelCell.getRow().setHeight((short) ExcelUtil.calculatePoiWidthSize(data.getHeight()));
                        data.setHeight(-1); //Asi no se vuelve a aplicar el estilo mas adelante
                    }
                    data.setAutoSize(false);
                    pict.resize(); //Como es XSSFWorkbook no deberia presentar problemas con el size y mantiene el original
                }
            } else {
                log.info("ImageCellProduce: Ignoring image on " + point);
            }
        }
    
    }
    
    

    miércoles, 6 de abril de 2016

    Provar en local enviar correos con Postman

    Creo que esto podría servir para cualquier tecnología. Pero me voy a enfocar en el plugin de Postman para wordpress en PHP.

    Pasos:

    1.) Debemos instalar Python con todos los utilitarios.

    2.) Ejecutar el comando en una terminal
    Nota: La terminal mostrara en consola todo los correos que se envíen a este servidor de pruebas.

    sudo python -m smtpd -n -c DebuggingServer localhost:45
    

    3.) Debemos ir a la configuración del postman del wordpress.
    Luego en Configuración manual.



    Dentro es simplemente de poner:

    Outgoing mail server hostname:......127.0.0.1
    Outgoing mail server port:................45
    Security:..............................................None
    Authentication:...................................None


    4.) Enviamos un mail de pruebas.


    5.) Este correo lo podremos ver en la terminal.



    jueves, 17 de marzo de 2016

    Kde Kate con React.js y Syntaxis Hightlight

    Para los que me siguen en el blog, saben que mi entorno de escritorio favorita es KDE. Y para desarrollo web en especial para Javascript utilizo Kate.
    Resulta que React.js esta muy de modo hoy en día, entonces me di a la tarea de investigar y aprender un poco.
    Para mi sorpresa, React.js tiene una sintaxis algo "Jodida". Y no se puede interpretar como Javascript normal.
    Entonces tome el Synstaxis Higtlight de Javascript que viene por defecto en Kate y lo edite para que funcione con React.js
    (Por cosas como estas amo el software libre).

    Simplemente tiene que colocar este archivo:

    
    
    
    
      
        
           break 
           case 
           catch 
           const 
           continue 
           debugger 
           default 
           delete 
           do 
           else 
           finally 
           for 
           function 
           if 
           in 
           instanceof 
           new 
           return 
           switch 
           this 
           throw 
           try 
           typeof 
           var 
           void 
           while 
           with 
        
        
           class 
           enum 
           export 
           extends 
           import 
           super 
    
          
           implements 
           interface 
           let 
           package 
           private 
           protected 
           public 
           static 
           yield 
        
        
           Infinity 
           NaN 
           false 
           null 
           true 
           undefined 
        
        
    
          
          
          
            
          
    
          
            
            
            
    
            
            
            
            
            
    
            
            
            
    
            
            
            
            
            
            
            
    
            
            
    
            
            
            
    
            
            
    
            
            
    
            
    
            
            
    
          
    
          
            
            
            
            
            
            
          
    
          
            
            
            
            
          
    
          
            
            
          
    
          
            
            
            
            
            
            
          
    
          
            
            
            
          
          
            
            
            
          
    
          
            
            
          
          
            
            
            
          
    
          
            
            
            
            
            
            
            
            
          
          
            
            
            
          
          
            
          
          
            
          
    
          
            
            
          
    
          
            
            
            
            
            
            
          
          
            
            
            
            
            
            
         
         
            
            
         
    
    
        
        
          
          
          
          
          
          
    
          
          
          
          
          
          
    
          
          
          
          
          
          
          
    
          
          
    
        
      
      
        
          
          
        
        
      
    
    

    con el nombre. react.xml.

    En el folder: ~/.kde/share/apps/katepart/syntax/

    Nota: Esta es la primera versión del asunto.
    Supongo que la tendré que ir madurando. Cualquier Feedback sera mas que bienvenido.

    domingo, 4 de octubre de 2015

    Instalar Nvidea Dirver/Steam en Debian 8


    Pasos:

    1. Agregar el el repositorio al administrador de paquetes
    sudo nano /etc/apt/sources.list
    #deb http://http.debian.net/debian/ jessie main contrib non-free
    sudo apt-get update
    

     2. Activar multiarquitectura
    sudo dpkg --add-architecture i386
    sudo apt-get update
    

    3. Instalar el paquete:
    sudo apt-get install libgl1-nvidia-glx:i386
    sudo apt-get install steam
    


    4. Crear el archivo:

    /etc/X11/xorg.conf.d/20-nvidia.conf

    Con el contenido:

    Section "Device"
            Identifier "My GPU"
            Driver "nvidia"
    EndSection

    5. Reiniciar

    AEM hablemos del arquetipo 11

    Cuando creamos un proyecto con AEM. Siempre es importante saber que arquetipo estamos usando. Pues esto me determinara que source, herramien...