Principios ACID


Principios ACID





El acrónimo ACID en el mundo de base de datos se refiere a un estándar de propiedades que garantizan que las transacciones de la base de datos se procesen de manera confiable.

Está especialmente enfocado en cómo una DB se recupera ante cualquier falla que pueda ocurrir al procesar una transacción.

Puntualmente este acrónimo es:

  • Atomicity
    Si cuando una operación consiste en una serie de pasos, bien todos ellos se ejecutan o bien ninguno, es decir, las transacciones son completas. Lo que hace que la serie de operaciones sea "indivisible". Una garantía de atomicidad evita que las actualizaciones de la base de datos se produzcan solo parcialmente
  • Consistency
    La coherencia es un término muy general, que exige que los datos deben cumplir con todas las reglas de validación. Todas las reglas de validación deben verificarse para garantizar la coherencia.
  • Isolation
    Esta propiedad asegura que una operación no puede afectar a otras.
  • Durability
    Esta propiedad asegura que una vez realizada la operación, esta persistirá y no se podrá deshacer aunque falle el sistema y que de esta forma los datos sobrevivan de alguna manera.


Cumpliendo estos 4 requisitos un sistema gestor de bases de datos puede ser considerado ACID Compliant.

Que una DB cumpla con las propiedades ACID, es un factor que ayuda a determinar cual opción tomar.

Ejemplos de bases de datos ACID-compliant:

  • Postgres
  • SQLite
  • MySQL with InnoDB
  • Oracle Database
  • MariaDB with XtraDB Engine
  • SQL Server Express


Principios SOLID


Principios Solid



SOLID es el acrónimo en el mundo de desarrollo de software, no sólo se limita a java sino a todos los lenguajes, que Michael Feathers creó, basado el paper “Design Principles and Design Patterns” sobre los principios de la programación orientada a objetos que Robert C. Martin(uncle bob) había recopilado en el año 2000.

Cada letra en inglés la palabra SOLID representa:


Recordar:
Cohesión es el grado en que el contenido de un módulo está relacionado entre sí.
Acoplamiento es el grado de interdependencia que tienen dos módulos de software entre sí.


SRP: Principio de responsabilidad única:



A class should have only one reason to change.

Robert C. Martin

Traducido al español sería “una clase debería tener una, y solo una, razón para cambiar”. Esto es precisamente, “razón para cambiar”, lo que Robert Martin identifica como “responsabilidad”. El propio Bob te lo resume asi nomás: “Gather together the things that change for the same reasons. Separate those things that change for different reasons”, es decir: “Reunir las cosas que cambian por las mismas razones. Separa aquellas que cambian por razones diferentes”.



OCP: Principio de abierto/cerrado:



Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.

Bertrand Meyer

El segundo principio de SOLID lo formuló Bertrand Meyer en 1988 en su libro “Object Oriented Software Construction” y dice: “Deberías ser capaz de extender el comportamiento de una clase, sin modificarla”. En otras palabras: las clases que usas deberían estar abiertas para poder extenderse y cerradas para modificarse.

Imaginemos un pintor que pinta figuras, como el siguiente ejemplo:

MAL

 class Figura {}
 
 class Cuadrado extends Figura {}
 
 class Circulo extends Figura {}
 class Pintor {
  void pinta (Collection<Figura> figuras) {
   for (Figura figura: figuras) {
    if (figura instanceof Cuadrado) {
     pinta((Cuadrado) figura);
    } else if (figura instanceof Circulo) {
     pinta((Circulo) figura);
    }
   }
  }

  void pinta (Cuadrado cuadrado) {
   // ...
  }

  void pinta (Circulo circulo) {
   // ...
  }
 }

El problema con el ejemplo anterior es que cuando necesitemos agregar nuevas figuras, el pintor debe modificarse violando el principio de abierto/cerrado. Una solución a este problema que permita extender pero se cierre a modificaciones es el siguiente:

OK

 interface Figura {
  void pinta();
 }

 class Cuadrado implements Figura {
  @Override
  public void pinta() {
   // ...
  }
 }
 class Circulo implements Figura {
  @Override
  public void pinta() {
   // ...
  }
 }
 class Pintor {
  void pinta (Collection<Figura> figuras) {
   for (Figura figura: figuras) {
    figura.pinta();
   }
  }
 }



LSP: Principio de substitución de Liskov:


T obj = new T();
 T obj = new S();

Subtype Requirement: Let φ(x) be a property provable about objects x of type T. Then φ(y) should be true for objects y of type S where S is a subtype of T.

Barbara Liskov

En español y dice que “Sea φ (x) una propiedad comprobable sobre objetos x de tipo T, Entonces φ (y) debería ser verdadero para los objetos Y de tipo S donde S es un subtipo de T”.
Dicho de otra manera: "las clases derivadas deben poder sustituirse por sus clases base".
Esto significa que los objetos deben poder ser reemplazados por instancias de sus subtipos sin alterar el correcto funcionamiento del sistema o lo que es lo mismo: si en un programa utilizamos cierta clase, deberíamos poder usar cualquiera de sus subclases sin interferir en la funcionalidad del programa.
Según el propio Robert Martin incumplir el principio de substitución de Liskov implica violar a su vez también el principio de Abierto-Cerrado.

Dado los siguientes arreglos de objetos:

 Integer[] array;
 Object[] arrayObjects;

¿Hay alguna relación de subtipo entre ellos?

Integer[] array = { 1,2,3 };
 Object[] arrayObjects = array;

Se puede decir que Integer[] es sub-tipo de Object[] ¿Pero es seguro?

 Integer[] array = { 1,2,3 };
 Object[] arrayObjects = array;
 arrayObjects[0] = "Hola";

Si intentamos ejeutar el siguiente código obtendremos la siguiente salida:

Exception in thread "main" java.lang.ArrayStoreException:
java.lang.String
at proves.Main.main(Main.java:12)

En algún momento de la historia existía solo java.util.Date... y llegó java.sql.Timestamp a hacerle compañía que es un Date + nanosegundos, su definición es:

public class Timestamp extends java.util.Date

¿Problemas? No...ninguno, ¿porqué preguntas?
Veamos lo siguiente:

Date date = new Date();
 Timestamp ts = new Timestamp(date.getTime());
 System.out.println(date.equals(ts));
 System.out.println(ts.equals(date));

Recordemos el javadoc para el metodo equals de object: Indicates whether some other object is "equal to" this one. The equals method implements an equivalence relation on non-null object references:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

Según el cual, el método implica debe ser simétrico: si x e y son iguales si y solo si y y x también lo son.

Pero...

Date date = new Date();
 Timestamp ts = new Timestamp(date.getTime());
 System.out.println(date.equals(ts));
 System.out.println(ts.equals(date));

Ejecutar el siguiente código resulta en un true seguido de un false




ISP: Principio de segregación:



Clients should not be forced to depend on methods they do not use.

Robert C. Martin

El cuarto principio definido por el propio Robert Martin dice que "Los clientes no deben ser forzados a depender de métodos que no usen."

En otras palabras es preferible contar con muchas interfaces que definan pocos métodos que tener una interface maestra que haga todo.

Dada la siguiente clase encargada de la comunicación, que decribe 2 métodos para enviar los mismo a través de un String o un Object:

public class Comunicador {
  public void enviaMensaje (String mensaje) {...}
  public void enviaMensaje (Object object) {...}
 }

Se nos pide agregar una encriptación para la misma, por lo tanto agregamos un método mas que se corresponde un nuevo Enum:

enum Encriptacion {
  NINGUNA, ENCRIPTACION_DEBIL, ENCRIPTACION_FUERTE
 }

 public class Comunicador {
  public void setEncriptacion (Encriptacion restriccion) {}
  public void enviaMensaje (String mensaje) {}
  public void enviaMensaje (Object object) {}
 }

Decidimos abstraer la clase a una interface para que distintos clientes puedan hacer uso de ella:

public interface Comunicador {
  static enum Encriptacion {
   NINGUNA, ENCRIPTACION_DEBIL, ENCRIPTACION_FUERTE
  }
  public void setEncriptacion (Encriptacion restriccion);
  public void enviaMensaje (String mensaje);
  public void enviaMensaje (Object object);
 }

Aun que estaríamos forzando a posibles clientes de implementar un nivel de encriptación que nunca necesiten:

public class ComunicadorImpl implements Comunicador {
  ...
 }

La solución es segregar en una interface el envio de los mensajes y en otra la encriptación:

public interface Comunicador {
  public void enviaMensaje (String mensaje);
  public void enviaMensaje (Object object);
 }
public interface Encriptable {
  static enum Encriptacion {
   NINGUNA, ENCRIPTACION_DEBIL, ENCRIPTACION_FUERTE
  }
  public void setEncriptacion (Encriptacion restriccion);
 }
public class ComunicadorImpl implements Comunicador, Encriptable {
  public void setEncriptacion (Encriptacion restriccion) {}
  public void enviaMensaje (String mensaje) {}
  public void enviaMensaje (Object object) {}
 }



DIP: Principio de inversión de dependencia:



A. High-level modules should not depend on lowlevel modules. Both should depend on abstractions.

B. Abstractions should not depend upon details. Details should depend upon abstractions.

Robert C. Martin


Depende de abstracciones, no de clases concretas es el último principio de la lista.

Así, Robert Martin recomendaría en español:

  • A - Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones.
  • B - Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones.

[Métodos] Generar código de barras y Códigos QR - Generación de códigos QR con ZXing


Generar código de barras y Códigos QR - Generación de códigos QR con ZXing



Los códigos QR o Quick Response Code son simple códigos de barras pero en 2 dimensiones que pueden ser leidos o escaneados por una cámara, como la de un teléfono móvil.

Un código QR consiste en cuadrados negros dispuestos en una cuadrícula cuadrada sobre un fondo blanco. Existen varias variantes de códigos QR que dependen del tamaño de los símbolos, el diseño, la codificación y la estructura.

Zxing es una librería para java y android que se pronuncia "Zebra Crossing" como el cruce peatonal de Abbey Road

Procedimiento:

Hay que agregar las dependencias de zxing-core y zxing-javase a nuestro propio proyeto

Con maven

 <dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>core</artifactId>
  <version>3.4.0</version>
 </dependency>
 <dependency>
  <groupId>com.google.zxing</groupId>
  <artifactId>javase</artifactId>
  <version>3.4.0</version>
 </dependency>
 

Con gradel

 compile "com.google.zxing:core:3.4.0"
 compile 'com.google.zxing:javase:3.4.0'
 

Manualmente añadir los jar al classpath descargandolos desde maven central


El siguiente paso es poner manos al código:

  • Crear una instancia de com.google.zxing.qrcode.QRCodeWriter
  • Obtener un BitMatrix a través de encodear con el objeto QRCodeWriter, pasando el texto, el tipo de codigo y un alto y ancho
  • Por último escribir en un archivo el bitmatrix a través de método MatrixToImageWriter.writeToPath definiendo la extensión de la imagen y el path.
 private static void generateQRCodeImage(String text, int width, int height, String filePath) throws WriterException, IOException {
  QRCodeWriter qrCodeWriter = new QRCodeWriter();
  BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);

  Path path = FileSystems.getDefault().getPath(filePath);
  MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
 }
 

Asegurarse de que el directorio del parametro filePath exista, porque no lo crea y lanza una excepción.

Ejecutando en un main normal de toda la vida, obtendremos:

public static void main(String[] args) throws Exception {
    generateQRCodeImage("Hola juli =)", 350, 350, "D:/dev/qrcodes/holajuli.png");
}

Resultado

[Métodos] Generar pdf con Jasper


Crear un reporte con Jasper Report



JasperReports es una biblioteca de creación de informes que tiene la habilidad de entregar contenido enriquecido al monitor, a la impresora o a ficheros PDF, HTML, XLS, CSV y XML... y no lo digo yo sino la wikipedia

Está escrito completamente en Java, su propósito principal es ayudar a crear documentos de tipo páginas, es de bajo licencia libre GNU, por lo que es Software libre.

Una de la más notoria ventaja es el diseño de sus templates a través de una sólida interfaz visual, componentes drag and drop para realizar el template xml por nosotros, además de que con un click realiza la compilación.




iReport Designer (v5.6.0) página de descarga



Nota mental: La ultima versión del iReport es la 5.6.0 del 28-May-2014 y al parecer solo funciona con java 7 en la variable de entorno JAVA_HOME. Pueden ser cambiado desde las configuraciones en la instalación, generalmente C:\Program Files (x86)\Jaspersoft\iReport-5.5.1\etc\ireport.conf o visitando la documentación

Jaspersoft Studio Eclipse plugin página del marketplace





La manera en que trabajar es la siguiente:

  • Se escribe un template xml con la extension .jrxml
  • Se compila con el motor de jasper para generar un archivo de extension .jasper
  • Se procesa junto a una fuente de datos: Collection de java o una conexion a la base de datos para obtener un ResultSet
  • Se obtiene como resultado un reporte! :D


Procedimiento

Crear un proyeto maven saltéandose la elección del arquetipo para luego agregar las dependencias a utilizar en el pom.xml:

 <!-- https://mvnrepository.com/artifact/net.sf.jasperreports/jasperreports -->
 <dependency>
  <groupId>net.sf.jasperreports</groupId>
  <artifactId>jasperreports</artifactId>
  <version>6.9.0</version>
 </dependency>
 

Tras hacer esto obtendremos un error, de que no encuentra la librería de itext.jar:2.1.7.js6, el problema es que en maven central no existe esa version sino una itext.jar:2.1.7.js2 y agregando esa ya maven es feliz

 <dependency>
  <groupId>com.lowagie</groupId>
  <artifactId>itext</artifactId>
  <version>2.1.7.js2</version>
 </dependency>
 
Adicionalmente vamos a tener que declarar el repositorio jasperreports y sus librerias de terceros ya que la versión de itext que espera es la versión 2.1.7.js4 y será desde aqui donde se tomen las librerias necesarias:

 <repositories>
  <repository>
   <id>jasperreports</id>
   <url>http://jasperreports.sourceforge.net/maven2</url>
  </repository>
  <repository>
   <id>jaspersoft-third-party</id>
   <url>http://jaspersoft.artifactoryonline.com/jaspersoft/third-party-ce-artifacts/</url>
  </repository>
 </repositories>
 

Con cualquiera de las opciones disponibles para crear los jrxml, se procede a crear un reporte como a uno más le guste.



Para empezar podemos arrastrar un static text y escribir el típico hola mundo, hello world, etc.


Nota mental: Al usar el iReport 'por defecto' tiende a usar el lenguaje como groovy dando exceptions en la compilación. Hay que editarlo desde las properties del reporte en la solapa de Report Inspector o bien remover el attributo language="groovy" en etiqueta root jasperReport luego de todas las declaraciones de esquemas. Ah y de paso agregar whenNoDataType="AllSectionsNoDetail" para que no evite no generar el pdf cuando no hay un fuente de datos para completar los mismos.

El archivo creado deberá ser dejado en la carpeta src/main/resources para encontrarlo a tiro.

 public static void imprime() throws JRException, IOException {
  System.out.println("obtenemos la plantilla JRXML como un inputstream");
  InputStream template = JasperRunnable.class.getResourceAsStream("/reporte.xml");

  System.out.println("compilamos el reporte desde el stream");
  JasperReport report = JasperCompileManager.compileReport(template);

  System.out.println("obtenemos la fuente de datos");
  Map<String, Object> sourceData = new HashMap<>();

  System.out.println("llenamos el reporte en un print object, con la fuente de datos");
  JasperPrint print = JasperFillManager.fillReport(report, sourceData);

  File pdf = File.createTempFile("output.", ".pdf");
  System.out.println("Lo exportamos a " + pdf.getAbsolutePath());
  JasperExportManager.exportReportToPdfStream(print, new FileOutputStream(pdf));
 }
 
La extensión puede ser tanto xml como jrxml dado que son simple archivos de texto plano con diferentes extension, pero para el caso es indistinto.

Ejecutando esta función en la clase main obtendremos una salida de consola como la siguiente:

obtenemos la plantilla JRXML como un inputstream
compilamos el reporte desde el stream
obtenemos la fuente de datos
llenamos el reporte en un print object, con la fuente de datos
Lo exportamos a C:\Users\Imago\AppData\Local\Temp\output.5354953787413152033.pdf

Dandonos como resultado, el mas simple de los pdf:



Es lo más básico de lo más básico que puede ofrecernos jasper report, pero es sólo el inicio.

[GIT] Git Flow - GitHub Flow


A la hora de trabajar con git, existen varios formas de lograr con éxito una buena organización. Existen 2 métodos que proponen una forma de trabajar bajo ciertas normas, ninguna resulta ser perfecta, ninguna cubre todos los casos y es posible que necesitemos nuestra forma de realizar un flujo de trabajo y conocer estos métodos nos brindará una idea como hacerlo.


GitFlow



Gitflow o flujo de git es una manera de trabajar ordenando el repositorio en varias ramas que se corresponden con cada fase del desarrollo de la aplicacion.


La propuesta de este flujo de trabajo cuenta con 5 ramas:

  • master
  • hot-fix
  • release
  • develop
  • feature

Master

Este modo de trabajo nos propone dejar master donde se encuentren las versiones finales, similar a los tags.

Desde master de desprende hot-fix, para tratar incidentes urgentes generalmente rapidos y cortitos.


Develop

Desde master nace la rama de develop, una especie de borrador de master. Desde aqui cada desarrollador crearia su propia rama de trabajo feature-xxx.

Desde ahi uno es libre de seguir creando tantos branch locales como se necesite. Lo importante es, un vez finalizado el trabajo, mergear a develop.

En este punto, nace release, para corregir los ultimos detalles y adecuar al entorno del cliente. Una vez lograda cerrar las caracteristicas del nuevo desarrollo, se integra en develop y desde esta ultima se devolveria a master. Para finalizar se crea el tag.



GitHubFlow



Githubflow o flujo de github, es una manera de trabajar mas minimalista, con solo una rama principal(master) y la rama de turno para generar cambios.


Las caracteristicas principales son:


Todo en master es deployable(desplegable a nivel productivo), esto es ideal a la hora de trabajar con integracion continua y delivery continuo.


Cada nueva caracteristica requiere hacer un branch desde master, y pusheando al remoto hasta lograr una version de pruebas.


Podria haber tantas ramas como caracteristicas simulteneas se requieran.


Si un compañero finalizo su trabajo e integro en master, al crear la nuestra desde la misma instancia, se puede traer sus cambios y sumarlos a los propios.



Los pasos a seguir en flujo de trabajo son:

  • Crea tu propia rama, desde master
  • Trabajar de manera local pusheando los commits a la rama remota
  • Cuando la rama este lista para el merge con master se abre un pull request.
  • Se conversa y revisa el codigo con el grupo de trabajo
  • Deploy y testing en produccion, los arreglos y adecuaciones de configuracion se realizan en este punto
  • Merge a master, luego tag.

[GIT] Operadores - Pull, Push y Fecth

Operadores en GIT

Colaborando: (ver también: git --help workflows)

       
    • Fetch
    • Descarga objetos y referencias de otro repositorio, pero no realiza ningun cambio, es como preguntar ¿Qué hay de nuevo?
  •    
    • Pull
    • Recupera e integra con otro repositorio o un branch local. Hace el fetch y actualiza el branch actual.
  •    
    • Push
    • Actualiza referencias remotas junto con objetos asociados, envia la serie de commits al repositorio remoto.

Actualizando referencias remotas >fetch<

Desde la documentacion local git-fetch

Syntaxis

git fetch [] [ […​]]
git fetch []
git fetch --multiple [] [( | )…​]
git fetch --all []
--all

Permite buscar en todos los branches remotos

--verbose ó -v

Vuelve la salida verbosa, o esa detalla en como han ido el procesamiento del comando

--tags ó -t

Fetchea todos todos los tags remotos dentro de los tags local con el mimsmo nombre

<repository>

Nombre o direccion del repositorio remoto donde se realizará el fetch


Fetch y Merge en una sola operacion: >pull<

Desde la documentacion local git-pull

Syntaxis

git pull [options] [ […​]]

Es la combinación de hacer git fetch && git merge FETCH_HEAD

Opciones de fetch

Son validas todas las opciones de fetch como --all --verbose, etc y las estrategias de merge --ignore-all-space

--rebase

Ejecuta fetch pero en lugar de hacer 'merge' realizará un 'rebase'


Commits
master A -- B -- C
feature  \ -- D -- E

Merge
master A -- B -- C -- F
feature  \ -- D -- E -- /

Rebase
master A -- B -- C
feature                \ -- D -- E
--commit y --no-commit

Realiza el merge y genera un auntocommit, caso contrario da la chance al usuario de tomar acciones

--squash y --no-squash

Realiza el mergue de los commits que se trae como uno solo, caso contrario actualiza cada commit en forma individual


Commiteando en el repositorio remoto: >push<

Desde la documentacion local git-push

Syntaxis

git push [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=]
[--repo=] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]
[-u | --set-upstream] [--push-option=]
[--[no-]signed|--sign=(true|false|if-asked)]
[--force-with-lease[=[:]]]
[--no-verify] [ […​]]
--all

Pushea todos los cambios en todos los branches locales

--tags

Pushea todos los tags, por defecto no se envian

-u ó --set-upstream

Agrega una referencia remota(tracking) al corriente branch

--verbose ó -v

Se ejecuta verbosamente

[Métodos] Crear un ejecutable (.exe) a partir de nuestro .jar de java con Launch4J


Launch4j es una herramienta para envolver aplicaciones Java distribuidas como jars in ejecutables nativos de Windows (es posible tambien envolverlos para Linux y Mac OS X)

Permite personalizar el icono de la app, crear un splash screen nativo al sistema, embeber una jre o redirigir a la pagina de descarga de Java en caso que no se encuentre disponible.

Se puede realizar con la tarea con el ejecutable como comandos de linea de consola, como tarea ant y construir con un plugin en maven.

Creando un ejecutable

Para la elaboracion del ejecutable con Launch4j necesitaremos



Principal.java

public class Principal {
    public static void main(String[] args) {
        String titulo = "Saludos con Launch4j";
        String message = "Hola juli =)";
        int messageType = JOptionPane.INFORMATION_MESSAGE;
        JOptionPane.showMessageDialog(null, message, titulo, messageType);
    }
}

Se le agrega la definicion de la clase main al plugin que genera el jar ejecutable

pom.xml

<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>com.github.dariozubaray</groupId>
 <artifactId>saludo-joptionpane</artifactId>
 <version>1.0.0-SNAPSHOT</version>
 <name>saludosJOptionPane</name>
 <description>simple saludo desde joptionpane</description>
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
     <archive>
      <manifest>
       <mainClass>com.github.dariozubaray.Principal</mainClass>
      </manifest>
     </archive>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>

Cuando ejecutamos el goal mvn package, obtendremos nuestro jar ejecutable.




Una vez dentro de launch4j, en la solapa de basic debemos configurar

  • OutputFile: es el archivo de salida con la extension .exe
  • Jar: el jar que queremos envolver

Luego bajo JRE debemos especificar al menos la version minima de java

  • El esquema soportado por launch4j es el versionado tradicional que consta de 2 números mayor.menor(en inglés: major.minor) EJ: 1.5
  • También es válido el versionado de 3 números mayor.menor.micro, como la fase de desarrollo. EJ: 1.8.0
  • Se admite también la fase de construccion EJ: 1.7.0_51
  • A partir de java 9 es válido indicar solo el número de version. EJ: 10

Construir el envoltorio desde el icono de engranaje, lo que nos preguntará de guardar la configuración como xml

Y eso es todo, en el panel inferior debe aparecer el mensaje de 'Successfully created + la ruta completa'



Utilizando Maven plugin

Para dejar en manos de maven la creacion del ejecutable con launch4j, debemos agregar en el pom el siguiente plugin

pom.xml

<plugin>
 <groupId>com.akathist.maven.plugins.launch4j</groupId>
 <artifactId>launch4j-maven-plugin</artifactId>
 <executions>
  <execution>
   <id>l4j-clui</id>
   <phase>package</phase>
   <goals>
    <goal>launch4j</goal>
   </goals>
   <configuration>
    <headerType>gui</headerType>
    <jar>target/saludo-joptionpane-1.0.0-SNAPSHOT.jar</jar>
    <outfile>target/archivoSalidaEjecutable.exe</outfile>
    <downloadUrl>http://java.com/download</downloadUrl>
    <classPath>
     <mainClass>com.github.dariozubaray.Principal</mainClass>
    </classPath>
    <jre>
     <bundledJre64Bit>false</bundledJre64Bit>
     <bundledJreAsFallback>false</bundledJreAsFallback>
     <minVersion>1.5</minVersion>
     <jdkPreference>preferJre</jdkPreference>
     <runtimeBits>64/32</runtimeBits>
    </jre>
   </configuration>
  </execution>
 </executions>
</plugin>

Posteriormente al guardado, podemos ejecutar la fase a partir de package, aunque con maven install hace mas de lo que se necesita es más rápido. El resultado será:



Personalizandolo

Para poersonalizar al menos un poco el ejecutable podemos incluir un icono y un screensplash que es la imagen mientras se carga el programa, para ello debemos modificar la clase main para que se tarde unos segundos antes de arrancar.



Principal.java

public class Principal {
    public static void main(String[] args) {
        try {
            Thread.sleep(5000);
        } catch(InterruptedException ie) {
            ie.printStackTrace();
        }
        String titulo = "Saludos con Launch4j";
        String message = "Hola juli =)";
        int messageType = JOptionPane.INFORMATION_MESSAGE;
        JOptionPane.showMessageDialog(null, message, titulo, messageType);
    }
}

En la pestaña de basic podemos incluir la 'icon' y en la propia de 'splash', luego de habilitarla, la imagen bmp para mostrar mientras se carga la app.

[Git] Comandos Rápidos para casos puntuales




  • Obtener la version que estoy usando

    git --version
    
    git version 2.14.3.windows.1
    

  • Ver y editar user/email

    #ver nombre de usuario
    git config user.name
    #ver email
    git config user.email
    
    #crear todas las propiedades de config
    git config --list
    
    #crear nombre de usuario
    git config --global user.name "<nombre>"
    
    #crear email
    git config --global user.email "<email>"
    

  • Ver y crear alias

    #ver lista de alias
    git config --get-regexp alias
    
    #crear alias
    git config --global alias.<nombre> "git <comando>"
    
    #crear alias del alias
    git config --global alias.alias "config --get-regexp ^alias\."
    

  • Crear branch local y pushearlo al remoto

    #crear branch y cambiarse al el
    git branch <nombre_branch> && git branch <nombre_branch>
    
    git push --set-upstream <remote_name> <nombre_branch>
    

  • Agregar y cambiar la url del repositorio remoto

    #para ver el repositorio remoto
    git remote -v
    #Cambiar el repositorio remoto existente
    git remote set-url <remote_name> <url>
    #Agregar un nuevo repositorio
    git remote add <remote_name> <url>
    

  • Clonar un solo branch remoto especifico

    git clone -b <branch_name> <url>
    #para version anteriores a 1.7.10
    git clone -b --single-branch <branch_name> <url>
    

  • Realizar un merge ignorando los espacios en blancos

    git merge -Xignore-all-space
    #O siendo mas espeficicos
    git merge -Xignore-space-change
    

  • Moverse a otro branch remoto especifico

    git fetch
    git checkout test
    #Multiples remotos
    git fetch <remote_name>
    git checkout -b <branch_name> <remote_name>/<branch_name>
    

  • Generar tags y pushearlos

    #ver tags locales
    git tag
    #crear un nuevo tag
    git tag -a <nombre_tag> -m "comentario"
    #enviar el tag al remoto
    git push <remote_name> --tags
    

  • Borrar un branch local y remoto

    git branch --delete <branch_name>
    git push <remote_name> --delete <branch_name>
    

  • Descartar cambios modificados o agregados al staged index

    #descartar cambios not staged
    git checkout -- .
    #descartar cambios to be committed
     git reset --hard
    

  • Borrar un commit local y remoto

    #hacer de cuenta que aca no paso nada
    git reset HEAD~1
    #no perder los cambios
    git reset HEAD^ --soft
    
    #borrar el commit en el remoto
    git reset HEAD^ --hard && git push <remote_name> -f
    
    #alt + 94 = ^  alt + 126 = ~