RSS

Archivo de la categoría: programación

Cosas relacionada con la programación

TDD

Metodología de pruebas bastante extendida cuyo acrónimo significa:

  • Inglés: Test Driven Development.
  • Español: Desarrollo guiado por pruebas.

Se utiliza generalmente para el desarrollo de pruebas unitarias y no es dependiente de ningún lenguaje. El proceso de desarrollo siguiendo esta metodología se compone de tres etapas diferentes:

  1. Se escriben las pruebas y se comprueba que fallan.
  2. Se implementa el mínimo código que hace que las pruebas se pasen exitosamente.
  3. Se refactoriza el código escrito.

La idea de la metodología es que los requisitos de negocio sean transformados en pruebas asegurando de este modo que al final el desarrollo, todos los requisitos se cumplen. También es evidente que utilizando esta metodología, otro de los objetivos que se alcanzan es el de tener una amplia cobertura de pruebas en nuestros proyectos, ya que nunca se va a desarrollar nada para lo que no se hayan escrito sus pruebas previamente. Esto deriva en que en las siguientes iteraciones del proyecto, el desarrollador que quiere introducir nuevos cambios puede confiar en que el código que va a modificar o va a utilizar en su desarrollo funciona e implementa de forma correcta los requisitos de negocio.

A la hora de la implementación, se pretende que el código siga dos principios básicos y ampiamente conocidos como son:

  • KISS: “keep is simple stupid”. Literalemnte traducido por “Mantenlo sencillo estupido”, aunque prefiero la traducción “Mantenlo estúpidamente sencillo”. Que nos viene a instar a mantener nuestros sistemas lo más simples posibles a través de buenas prácticas de diseño.
  • YAGNI: “You aren´t gonna need it”. Literalmente traducido por “No lo vas a necesitar”. Este principio nos insta a no implementar cosas que no se van a utilizar, ni siquiera aunque pensemos que en un futuro quizás lo vayamos a hacer, porque en la mayoría de las ocasiones, ese futuro nunca llega.

Pero bueno, después de toda esta introducción teórica, vamos a implementar algo.

Primera Fase: Escribir las pruebas y comprobar que fallan.

public interface Calculator {
    int add(int a, int b);
    int subs(int a, int b);
    ....
}
public class MyCalculator implements Calculator {
    public int add(int a, int b) {
        return 0;
    }

    public int subs(int a, int b) {
        return 0;
    }

    ...
}
public class MyCalculatorTest {

    Calculator calc;

    @Before
    public void setUp() {
        calc = new MyCalculator();
    }

    @Test
    public void addTest() {
        assertEquals(2, calc.add(1, 1));
    }

    @Test
    public void subsTest() {
        assertEquals(1, calc.subs(2, 1));
    }

    ...
}

Segunda Fase: Implementar el mínimo código

public class MyCalculator implements Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subs(int a, int b) {
        return a - b;
    }

    ...
}

Tercera fase: Refactorizar nuestro código

En este caso, está tercera fase obviamente no tiene mucho sentido ya que el código se ha hecho lo más simple posible para que nos fijemos solo en el proceso de TDD y no en el código. Pero por si alguno no está familiarizado con el término refactorizar, os dejo el enlace de su definición: Refactorización

Tras esto tendríamos listo nuestro código con nuestras pruebas y la implementación de nuestra lógica de negocio, con lo que podríamos pasar al siguiente requisito.

Se que es una pequeña (muy pequeña) introducción al término de TDD pero creo que puede ser útil para aquellos que lo desconozcan o nunca lo hayan utilizado. Nos vemos.

 
Deja un comentario

Publicado por en 30 septiembre, 2014 en Desarrollo ágil, programación

 

Añadir una libraría a nuestro repositorio maven

Aunque muchas veces lo parezca, maven no tiene todas las librerías que podamos necesitar, generalmente por problemas de licencias y demás, o simplemente, si queremos añadir a nuestro repositorio local una librería que hemos creado nosotros mismos para poder utilizarla en otros proyectos, en ambos casos, podemos instalar de forma manual dicha librería en nuestros repositorios locales.

¿Qué necesitamos para ello? Nada más fácil, la librería, un pequeño comando de consola, y saber un poco que estamos haciendo, que es lo que pretendo explicar en este artículo.

Imaginemos que como librería para el ejemplo vamos a utilizar una llamada “example-1.0.jar”, y que dicha librería es la que queremos añadir a nuestro repositorio local.

El comando a ejecutar, es tan simple como:

mvn install:install-file -Dfile=<libraryName> -DgroupId=<groupId> -DartifactId=<artifactId> -Dversion=<version> -Dpackaging=jar

Como veis es bastante simple, y cualquiera ligeramente familiarizado con maven puede reconocer que son cada uno de los parámetros, ya que son los habituales datos que rellenamos cuando añadimos las dependencias en nuestro “pom.xml”.

Con nuestra librería ejemplo, esto quedaría algo así:

mvn install:install-file -Dfile=example-1.0.jar -DgroupId=org.example -DartifactId=example -Dversion=1.0 -Dpackaging=jar

Tras esto, solo tendríamos que ir a nuestro proyecto e incluir la dependencia de la forma habitual:

<dependency>
    <groupId>org.example</groupId>
    <artifactId>example</artifactId>
    <version>1.0</version>
</dependency>

Y con esto ya estaríamos. Nos vemos.

 
Deja un comentario

Publicado por en 8 agosto, 2014 en prácticos, programación

 

MyBatis: Herencia de objectos

Hoy tengo uno de esos casos algo peculiares para los cuales no hay una solución buena o quizás todas sean buenas, nunca se sabe. De lo que estoy seguro es de que hay otras soluciones, y seguro que muchas de ellas mejores, sobre todo, porque yo estoy empezando a trabajar ahora con MyBatis y mis conocimientos sobre este framework no son muy extensos aún. Pero bueno, como ya sabéis el motivo del blog es aprender, y una forma de hacer esto es escribir lo que uno aprende y, posteriormente, revisar las cosas cuando uno adquiere más conocimiento.

Por ponernos en situación, el caso es este: Imaginemos que tenemos una aplicación con tres clases, las cuales extienden unas de otras, de forma que:

  • La clase A no extiende de ninguna.
  • La clase B extiende a A.
  • La clase C extiende a B.

En esta aplicación se entiende como un objeto completo a la clase C, pero a lo largo de la aplicación en determinadas ocasiones solo se requieren los datos que posee A o B, no siendo necesario tener el objeto al completo.

Además de este esquema de clases, en la BBDD, se decidió representar esta jerarquía de clases de igual modo, de forma que tenemos una tabla por cada clase y todas ellas comparten el mismo identificador.

Tras todo esto, se decidió implementar en MyBatis cumpliendo todas las restricciones y necesidades.

Antes de seguir leyendo, este artículo no es un tutorial de MyBatis (probablemente escriba uno, pero no hoy). Este artículo es solo la resolución de un caso muy concreto, otra de estas cosas que surgen y hay que solucionar sin poderse replantear el diseño de la aplicación.

Para ver como resolver esto, y repito, habrá muchas y mejores soluciones, vamos a hacer un pequeño proyecto donde:

  • La clase A será la clase “Mammal”. Con una propiedad “age” y un “id”.
  • La clase B será la clase “Human”. Con una propiedad “name” y un “id”.
  • La clase C será la clase “Gender”. Con una propiedad “gender” y un “id”.

No hagáis mucho caso a los nombre de las clases y centrados en las relaciones.

Para el ejemplo, vamos a utilizar Java y una BBDD PostgreSQL.

Lo primero, es crea un pequeño proyecto maven y añadirle las siguientes dependencias:

<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>org.example</groupId>
    <artifactId>MyBatis</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>
    <name>MyBatis</name>
	
    <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
	
    <dependencies>
	
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.7</version>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1101-jdbc41</version>
        </dependency>
	
    </dependencies>
	
    <build>
        <finalName>mybatis</finalName>
    </build>
</project>

El siguiente paso, si no lo hemos hecho ya, es crear una BBDD para nuestro ejemplo:

drop table if exists mammal;

create table mammal (
    id integer primary key, 
    age integer
);

drop table if exists human;

create table human (
    id integer primary key, 
    name varchar(50)
);

drop table if exists gender;

create table gender (
    id integer primary key, 
    gender varchar(50)
);

Tras esto, vamos a hacer una configuración básica de MyBatis para que conecte con nuestra BBDD:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- Alias generation -->
    <typeAliases>
        <package name="org.example.model" />
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="UNPOOLED">
                <property name="driver" value="org.postgresql.Driver" />
                <property name="url" value="jdbc:postgresql:earthlife" />
                <property name="username" value="postgres" />
                <property name="password" value="toor" />
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="org/example/model/MammalMapper.xml" />
        <mapper resource="org/example/model/HumanMapper.xml" />
        <mapper resource="org/example/model/GenderMapper.xml" />
    </mappers>

</configuration>

Y ya nos lanzamos a la implementación.

En primer lugar nuestros objectos:

package org.example.model;

public class Mammal {
    private int id;
    private int age;

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return this.age;
    }

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

}
package org.example.model;

public class Human extends Mammal {
    private int id;
    private String name;

    @Override
    public int getId() {
        return this.id;
    }

    @Override
    public void setId(int id) {
        this.id = id;
        super.setId(id);
    }

    public String getName() {
        return this.name;
    }

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

}
package org.example.model;

public class Gender extends Human {
    private int id;
    private String gender;

    @Override
    public int getId() {
        return this.id;
    }

    @Override
    public void setId(int id) {
        this.id = id;
        super.setId(id);
    }

    public String getGender() {
        return this.gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

}

En segundo lugar, los interfaces de los Mappers:

package org.example.mappers;

import java.util.List;

import org.example.model.Mammal;

public interface MammalMapper {
    Mammal getMammalById(int id);

    List<Mammal> getAllMammals();

    int insertMammal(Mammal mammal);

    int updateMammal(Mammal mammal);

    int deleteMammal(int id);
}
package org.example.mappers;

import java.util.List;

import org.example.model.Human;

public interface HumanMapper {
    Human getHumanById(int id);

    List<Human> getAllHumans();

    int insertHuman(Human human);

    int updateHuman(Human human);

    int deleteHuman(int id);

    Human getHumanMammalById(int id);

    List<Human> getAllHumanMammals();

    int insertHumanMammal(Human human);

    int updateHumanMammal(Human human);

    int deleteHumanMammal(int id);
}
package org.example.mappers;

import java.util.List;

import org.example.model.Gender;

public interface GenderMapper {
    Gender getGenderById(int id);

    List<Gender> getAllGenders();

    int insertGender(Gender gender);

    int updateGender(Gender gender);

    int deleteGender(int id);

    Gender getGenderHumanById(int id);

    List<Gender> getAllGenderHumans();

    int insertGenderHuman(Gender gender);

    int updateGenderHuman(Gender gender);

    int deleteGenderHuman(int id);

    Gender getGenderHumanMammalById(int id);

    List<Gender> getAllGenderHumanMammals();

    int insertGenderHumanMammal(Gender gender);

    int updateGenderHumanMammal(Gender gender);

    int deleteGenderHumanMammal(int id);
}

Y, por último, los Mappers en XML:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.example.mappers.MammalMapper" >

    <resultMap type="Mammal" id="MammalResultMap">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="age" property="age" jdbcType="INTEGER" />
    </resultMap>
    
    <select id="getMammalById" parameterType="int" resultMap="MammalResultMap">
        select id,
               age
          from mammal
         where id = #{id}
    </select>
    
    <select id="getAllMammals" parameterType="int" resultMap="MammalResultMap">
        select id,
               age
          from mammal
    </select>
    
    <insert id="insertMammal" parameterType="Mammal">
        insert into mammal
                    (id, age)
             values (#{id, jdbcType=INTEGER}, #{age, jdbcType=INTEGER})
    </insert>
    
    <update id="updateMammal" parameterType="Mammal">
        update mammal
           set age = #{age, jdbcType=INTEGER}
         where id = #{id, jdbcType=INTEGER}
    </update>
    
    <delete id="deleteMammal" parameterType="int">
        delete from mammal
         where id = #{id, jdbcType=INTEGER}
    </delete>
    
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.example.mappers.HumanMapper" >

    <resultMap type="Human" id="HumanResultMap">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
    </resultMap>
    
    <resultMap type="Human" id="HumanMammalResultMap">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="age" property="age" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
    </resultMap>
    
    <!-- Human -->
    
    <select id="getHumanById" parameterType="int" resultMap="HumanResultMap">
        select id,
               name
          from human
         where id = #{id}
    </select>
    
    <select id="getAllHumans" parameterType="int" resultMap="HumanResultMap">
        select id,
               name
          from human
    </select>
    
    <insert id="insertHuman" parameterType="Human">
        insert into human
                    (id, name)
             values (#{id, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR})
    </insert>
    
    <update id="updateHuman" parameterType="Human">
        update human
           set name = #{name, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER}
    </update>
    
    <delete id="deleteHuman" parameterType="int">
        delete from human
         where id = #{id, jdbcType=INTEGER}
    </delete>
    
    <!-- Human + Mammal -->
    
    <select id="getHumanMammalById" parameterType="int" resultMap="HumanMammalResultMap">
        select h.id,
               m.age,
               h.name
          from human h
          left outer join mammal m on h.id = m.id
         where h.id = #{id}
    </select>
    
    <select id="getAllHumanMammals" parameterType="int" resultMap="HumanMammalResultMap">
        select h.id,
               m.age,
               h.name
          from human
          left outer join mammal m on h.id = m.id
    </select>
    
    <insert id="insertHumanMammal" parameterType="Human">
        insert into mammal
                    (id, age)
             values (#{id, jdbcType=INTEGER}, #{age, jdbcType=INTEGER});
        insert into human
                    (id, name)
             values (#{id, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR})
    </insert>
    
    <update id="updateHumanMammal" parameterType="Human">
        update mammal
           set age = #{age, jdbcType=INTEGER}
         where id = #{id, jdbcType=INTEGER};
        update human
           set name = #{name, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER}
    </update>
    
    <delete id="deleteHumanMammal" parameterType="int">
        delete from human
         where id = #{id, jdbcType=INTEGER};
        delete from mammal
         where id = #{id, jdbcType=INTEGER}
    </delete>
    
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="org.example.mappers.GenderMapper" >

    <resultMap type="Gender" id="GenderResultMap">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="gender" property="gender" jdbcType="VARCHAR" />
    </resultMap>
    
    <resultMap type="Gender" id="GenderHumanResultMap">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="gender" property="gender" jdbcType="VARCHAR" />
    </resultMap>
    
    <resultMap type="Gender" id="GenderHumanMammalResultMap">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="age" property="age" jdbcType="INTEGER" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="gender" property="gender" jdbcType="VARCHAR" />
    </resultMap>
    
    <!-- Gender -->
    
    <select id="getGenderById" parameterType="int" resultMap="GenderResultMap">
        select id,
               gender
          from gender
         where id = #{id}
    </select>
    
    <select id="getAllGenders" parameterType="int" resultMap="GenderResultMap">
        select id,
               gender
          from gender
    </select>
    
    <insert id="insertGender" parameterType="Human">
        insert into gender
                    (id, gender)
             values (#{id, jdbcType=INTEGER}, #{gender, jdbcType=VARCHAR})
    </insert>
    
    <update id="updateGender" parameterType="Human">
        update gender
           set gender = #{gender, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER}
    </update>
    
    <delete id="deleteGender" parameterType="int">
        delete from gender
         where id = #{id, jdbcType=INTEGER}
    </delete>
    
    <!-- Gender + Human -->
    
    <select id="getGenderHumanById" parameterType="int" resultMap="GenderHumanResultMap">
        select g.id,
               h.name,
               g.gender
          from gender g
          left outer join human h on g.id = h.id
         where g.id = #{id}
    </select>
    
    <select id="getAllGenderHumans" parameterType="int" resultMap="GenderHumanResultMap">
        select g.id,
               h.name,
               g.gender
          from gender g
          left outer join human h on g.id = h.id
    </select>
    
    <insert id="insertGenderHuman" parameterType="Gender">
        insert into human
                    (id, name)
             values (#{id, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR});
        insert into gender
                    (id, gender)
             values (#{id, jdbcType=INTEGER}, #{gender, jdbcType=VARCHAR})
    </insert>
    
    <update id="updateGenderHuman" parameterType="Gender">
        update human
           set name = #{name, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER};
        update gender
           set gender = #{gender, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER}
    </update>
    
    <delete id="deleteGenderHuman" parameterType="int">
        delete from gender
         where id = #{id, jdbcType=INTEGER};
        delete from human
         where id = #{id, jdbcType=INTEGER}
    </delete>
    
    <!-- Gender + Human + Mammal -->
    
    <select id="getGenderHumanMammalById" parameterType="int" resultMap="GenderHumanMammalResultMap">
        select g.id,
               m.age,
               h.name,
               g.gender
          from gender g
          left outer join human h on g.id = h.id
          left outer join mammal m on g.id = m.id
         where g.id = #{id}
    </select>
    
    <select id="getAllGenderHumanMammals" parameterType="int" resultMap="GenderHumanMammalResultMap">
        select g.id,
               m.age,
               h.name,
               g.gender
          from gender g
          left outer join human h on g.id = h.id
          left outer join mammal m on g.id = m.id
    </select>
    
    <insert id="insertGenderHumanMammal" parameterType="Gender">
        insert into mammal
                    (id, age)
             values (#{id, jdbcType=INTEGER}, #{age, jdbcType=INTEGER});
        insert into human
                    (id, name)
             values (#{id, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR});
        insert into gender
                    (id, gender)
             values (#{id, jdbcType=INTEGER}, #{gender, jdbcType=VARCHAR});
    </insert>
    
    <update id="updateGenderHumanMammal" parameterType="Gender">
        update mammal
           set age = #{age, jdbcType=INTEGER}
         where id = #{id, jdbcType=INTEGER};
        update human
           set name = #{name, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER};
        update gender
           set gender = #{gender, jdbcType=VARCHAR}
         where id = #{id, jdbcType=INTEGER}
    </update>
    
    <delete id="deleteGenderHumanMammal" parameterType="int">
        delete from gender
         where id = #{id, jdbcType=INTEGER};
        delete from human
         where id = #{id, jdbcType=INTEGER};
        delete from mammal
         where id = #{id, jdbcType=INTEGER}
    </delete>
    
</mapper>

Como podéis ver, todo está preparado para poder trabajar con los tres objetos a lo largo de todas la aplicación, y que para aquellos que heredan se pueda obtener el objeto entero con todas sus propiedades, o solo partes de dicho objeto.

La única cosa digna de mención, ya que el código es fácilmente entendible, es la utilización del objeto “super” en los constructores, para poder hacer una asignación encadenada de dicho “id” ya que este es compartido por los tres objetos en las tres tablas. Si no lo añadiéramos, tendríamos en muchas ocasiones los ids de los objetos padres a null.

Aunque otra cosa que debería de nombrar es que el código no es independiente de la BBDD que utilicemos. Quiero decir, PostgreSQL soporte la ejecución consecutiva de varias instrucciones tal y como están en los Mappers, pero si utilizáramos una BBDD Oracle, por ejemplo, tendríamos que encerrar esas sentencias consecutivas entre un “begin” y un “end;”:

begin
    select ...;
    select ...;
    ...
end;

Estoy casi seguro de que se puede acortar mucho más el código trabajando con herencia de los objetos resultado en MyBatis o quizás reutilizando las sentencias SQL de unos mappers a otros, pero de momento, eso, está aún por investigar.

Nos vemos.

 
Deja un comentario

Publicado por en 3 agosto, 2014 en programación

 

El límite está en tu mente no en el lenguaje

Se que por el título del artículo, más de uno pensará que me voy a poner a filosofar sobre unas cosas u otras, pero nada dista más de mi intención. Lo que pasa es que al igual que no se porque he escrito la porción de código que os traigo hoy, no sabía que título ponerle.

Hoy es uno de esos días donde en una discusión sobre diseño, salta alguien diciendo si tal cosa o tal otra se puede o no se puede hacer, y si Java no lo soporta y ese tipo de discusiones que no llegan a ningún lado. En concreto, era el paso como parámetro de una función (véase que estamos por razones de proyecto usando la versión 1.7 y no la 1.8). Es cierto, que en este punto no te queda más remedio que concederle la razón, sobre todo si entra en comparaciones con JavaScript (salvando las distancias). Pero, he aquí que a uno después de estas discusiones, se le queda un no sé qué que que se yo que tiene que ponerse a escribir algo de código a ver que puede hacer.

La idea, era escribir una operación de CRUD que en ciertas ocasiones necesita crear una transacción y en otras no. Lo más común es duplicar los métodos, en uno la lógica y en otro el manejo de la transacción y la llamada al que tiene la lógica (seguro que habrán métodos mejores, peores y de todo tipo, pero no es el punto de este artículo).

Pues bien, para hacer una aproximación de como pasar funciones como parámetros (sin que el lenguaje lo permita) yo me he decantado por una clase abstracta. A continuación, os pongo el código y luego, lo explicaré un poco, aunque es muy básico.

package com.wordpress.infow.chorradas;

import org.apache.log4j.Logger;

import com.wordpress.infow.db.TransactionManager;

public abstract class GenericExec {

    static Logger logger = Logger.getLogger(GenericExec.class);

    public static final int CREATE = 0;
    public static final int READ = 1;
    public static final int UPDATE = 2;
    public static final int DELETE = 3;

    abstract public String create(Object obj, TransactionManager tr);

    abstract public Object read(Object obj, TransactionManager tr);

    abstract public void update(Object obj, TransactionManager tr);

    abstract public void delete(Object obj, TransactionManager tr);

    public Object withTransaction(GenericExec generic, Object data, int operation) {
        Object obj = null;

        TransactionManager tr = new TransactionManager();

        try {
            tr.initTransaction();

            switch (operation) {
                case CREATE:
                    obj = generic.create(data, tr);
                    break;

                case READ:
                    obj = generic.read(data, tr);
                    break;

                case UPDATE:
                    obj = generic.update(data, tr);
                    break;

                case DELETE:
                    obj = generic.delete(data, tr);
                    break;
            }

            tr.commit();
        } catch (Exception e) {
            GenericExec.logger.error(generic.getClass() + "::" + operation + " " + e.getMessage());
        } finally {
            tr.closeTransaction();
        }

        return obj;
    }
}

Como se puede ver, la clase abstracta obliga a implementar los métodos que deseamos, las operaciones de CRUD, y posee la implementación de la función que nos va a permitir ejecutar estas con una transacción alrededor. Todo muy básico. Además, de esta clase van a extender muchas otras que va a recibir parámetros de tipo diferente y devolver parámetros de tipo diferente para cada una de las clases que heredan.

Yo creo que no necesita más explicación. Tiene algunas pegas, como que hay que tener la precaución de realizar los casting apropiados desde el objeto Object al que deseamos utilizar, pero por lo demás es bastante manejable.

De nuevo, recordados que esto solo es un juguete, una chorrada implementada a partir de un debate sobre algo, y sin más sentido que como reto o idea, y ver que aunque muchas veces un lenguaje no nos provee de algo, siempre podemos implementarnos algo, como reza el título del artículo, los límites muchas veces están en la mente del desarrollado no en el lenguaje. Y no hablo de inteligencia, sino de ganas de jugar un rato con el lenguaje o falta de tiempo, o cosas de este estilo.

Bueno, espero que como curiosidad os haya gustado. Si alguien tiene alguna duda, preguntad sin miedo. Nos vemos.

 
Deja un comentario

Publicado por en 31 julio, 2014 en programación

 

Planificar tareas en Java

En algunas ocasiones nos vemos en la necesidad de que nuestras aplicaciones lancen alguna tarea en segundo plano para llevar a cabo algún procedimiento, generar algún informe, recolectar nuevas alertas, … este tipo de cosas. En este caso lo mejor es lanzarlas en segundo plano y no en el hilo principal. Para esto, Java nos ofrece tres posibilidades diferentes que vamos a ver a continuación a modo de chuleta de fácil y rápido acceso.

La primera de las formas es usando un simple hilo. Crearíamos el hilo con la tareas, lo lanzaríamos indefinidamente y le asignaríamos un intervalo de espera. Esto quedaría algo así:

public class Example1 {
    public static void main(String[] args) {
        final long interval = 2000; // Each 2 seconds
        Runnable runnable = new Runnable() {
            public void run() {
                while (true) {
                    System.out.println("I am here!!!");
                    try {
                        Thread.sleep(interval);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();
    }
}

Como podéis ver es bastante simple. Basta con crear el objeto Runnable, crear el comportamiento que deseamos y lanzarlo. No tenemos mucho control sobre cuando empezar o parar el hilo y el proceso se lanzará de forma inmediata, pero el objetivo era ser simple.

El siguiente ejemplo que vamos a ver cubre las necesidades que no nos ofrece la solución anterior, que en definitiva son, tener un poco más de control sobre muestro proceso. Para ello vamos a utilizar las clases Timer y TimerTask. Además, la instancia de Timer es thread-safe.

public class Example2 {
    public static void main(Strings[] args) {
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("I am here!!!");
            }
        };

        Timer timer = new Timer();
        long delay = 0;
        long interval = 2000;

        timer.scheduleAtFixedRate(task, delay, interval);
    }
}

Como se puede ver en este ejemplo, aunque un poquito más complejo, nos ofrece la posibilidad de definir más parámetros para nuestra tarea.

El tercer y último método que vamos a ver, nos permite aún más flexibilidad de la que ya teníamos en el caso anterior. Las clases que nos permiten la implementación de esta última fueron añadidas en Java SE 5.

public class Example3 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
                system.out.println("I am here!!!");
            }
        };

        ScheduledExecutorService ses = Executors.
                newSingleThreadScheduledExecutor(runnable, 0, 1, TimeUnit.SECONDS);
    }
}

Este como vemos es en el que menos código escribimos, el más configurable a la hora de lanzar nuestro proceso y, además, aunque aquí no lo hemos usado, nos ofrece la posibilidad de tener un Pool de hilos para las ejecuciones.

Bueno, hasta aquí todo por hoy. Nos vemos.

Nota: Basado en el post How to Schedule a task to run in an interval.

 
2 comentarios

Publicado por en 14 abril, 2014 en programación

 

JavaFX – Nuevo repositorio

Hace ya un par de meses os anuncié que había creado una cuenta en Bitbucket donde albergar repositorios Git, algunos de ellos públicos otros privados, donde iba a albergar cosillas que fuera haciendo. De hecho, en el blog hay publicadas varias entradas con ejemplos en JavaEE y su código fuente correspondiente está albergado en estos repositorios.

Pues bien, hoy uno de esos repositorios que he creado públicos es el que va a estar dedicado a JavaFX, podéis encontrarlo aquí. De momento, solo he añadido los proyectos que se corresponde con el tutorial de JavaFX de Oracle en su sección “Getting Started…“, pero espero ir añadiendo más cosillas poco a poco.

Bueno, solo era comentar simplemente esto. Nos vemos.

 
Deja un comentario

Publicado por en 7 noviembre, 2013 en programación

 

Simplificando proyectos

Hoy, solo os traigo una charla de Adam Bien sobre el código que sobra en nuestros proyectos y la enorme cantidad de veces que tenemos en ellos mucho más de lo que necesitamos. Me ha sorprendio, entre otras cosas a parte de resultarme interesante, la cantidad de cosas que comenta que no se deberían hacer y que si que se hacen en la mayoría de proyectos grandes en los que he participado. Obviamente, esto es una opinión de él, pero con bastante sentido común muchas de las cosas que comenta.

Para quien no lo conozca, es un Freelancer que lleva trabajando muchísimos años en Java, y como él dice, aún lo disfruta. Además, ha escrito un par de libros (que tengo en mi lista para leer) y, de vez en cuando, da charlas sobre JavaEE. Los libros son:

Pero bueno, os dejo su página si queréis echarle un ojo: Adam Bien

El video, como ya he dicho, es bastante interesante. Su duración es de menos de una hora (unos 45 minutos) y, aunque está en inglés, es fácimente entendible.

Espero que os guste. Nos vemos.

 
Deja un comentario

Publicado por en 4 octubre, 2013 en JavaEE, programación