Java - Estándares de programación. Nomenclaturas. Buena praxis.

1. Estándares de programación

1.1. Introducción

El objeto del presente documento es el establecimiento de los estándares o convenciones de programación empleados en el desarrollo de software sobre la plataforma Java. Este modelo de programación está basado en los estándares recomendados por Sun Microsystems, que han sido difundidos y aceptados ampliamente por toda la comunidad Java, y que han terminado por consolidarse como un modelo estándar de programación de facto.

Estas normas son muy útiles por muchas razones, entre las que destacan:


  • Facilitan el mantenimiento de una aplicación. Dicho mantenimiento constituye el 80% del coste del ciclo de vida de la aplicación.

  • Permite que cualquier programador entienda y pueda mantener la aplicación. En muy raras ocasiones una misma aplicación es mantenida por su autor original.

  • Los estándares de programación mejoran la legibilidad del código, al mismo tiempo que permiten su compresión rápida.



1.2. Organización de ficheros

Las clases en Java se agrupan en paquetes. Estos paquetes se deben organizar de manera jerárquica, de forma que todo código desarrollado para el Ayuntamiento de Málaga tendrá que estar incluido dentro del paquete "eu.malaga". 
Dentro del paquete principal las clases se organizarán en subpaquetes en función del área, organismo o sección del Ayuntamiento al que pertenezca el código desarrollado. Por ejemplo, si estamos desarrollando un servicio web de inscripción a un curso de programación Java del IMFE las clases de dicho servicio se incluirían en el paquete "eu.malaga.imfe.webservices.cursojava" o similar.

Un fichero consta de secciones que deben estar separadas por líneas en blanco y comentarios opcionales que identifiquen cada sección.

Deben evitarse los ficheros de gran tamaño que contengan más de 1000 líneas. En ocasiones, este tamaño excesivo provoca que la clase no encapsule un comportamiento claramente definido, albergando una gran cantidad de métodos que realizan tareas funcional o conceptualmente heterogéneas.

1.2.1. Fichero fuente Java (.java)

Cada fichero fuente Java debe contener una única clase o interfaz pública. El nombre del fichero tiene que coincidir con el nombre de la clase. Cuando existan varias clases privadas asociadas funcionalmente a una clase pública, podrán colocarse en el mismo fichero fuente que la clase pública. La clase pública debe estar situada en primer lugar dentro del fichero fuente.
En todo fichero fuente Java distinguimos las siguientes secciones:


  • Comentarios de inicio.

  • Sentencia de paquete.

  • Sentencias de importación.

  • Declaraciones de clases e interfaces.



1.2.1.1. Comentarios de inicio

Todo fichero fuente debe comenzar con un comentario que incluya el nombre de la clase, información sobre la versión del código, la fecha y el copyright. El copyright indica la propiedad legal del código, el ámbito de distribución, el uso para el que fue desarrollado y su modificación. 

Dentro de estos comentarios iniciales podrían incluirse adicionalmente comentarios sobre los cambios efectuados sobre dicho fichero (mejora, incidencia, error, etc.). Estos comentarios son opcionales si los ficheros están bajo un sistema de control de versiones bien documentado, en caso contrario se recomienda su uso. Estos comentarios constituyen el historial de cambios del fichero. Este historial es único para cada fichero y permitirá conocer rápidamente el estado y la evolución que ha tenido el fichero desde su origen.

A continuación se muestra un comentario de inicio para la clase "JceSecurity.java".


/*
 * @(#)JceSecurity.java 1.50 04/04/14
 * 
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/**
 * This class instantiates implementations of JCE engine classes from
 * providers registered with the java.security.Security object.
 *
 * @author Jan Luehe
 * @author Sharon Liu
 * @version 1.50, 04/14/04
 * @since 1.4
 */


1.2.1.2. Sentencias de paquete

La primera línea no comentada de un fichero fuente debe ser la sentencia de paquete, que indica el paquete al que pertenece(n) la(s) clase(s) incluída(s) en el fichero fuente. Por ejemplo,


package javax.crypto;


1.2.1.3. Sentencias de importación

Tras la declaración del paquete se incluirán las sentencias de importación de los paquetes necesarios. Esta importación de paquetes obligatorios seguirá el siguiente orden:


  • Paquetes del JDK de java.

  • Paquetes de utilidades no pertenecientes al JDK de Java, de frameworks de desarrollo o de proyectos opensource tales como apache, hibernate, springframework, etc.

  • Paquetes desarrollados para el Ayuntamiento de Málaga.

  • Paquetes de la aplicación.



Se recomienda minimizar en la medida de lo posible el uso de importaciones del tipo "package.*", pues dificultan la comprensión de las dependencias existentes entre las clases utilizadas por la aplicación. En caso contrario, se recomienda utilizar comentarios de línea tras la importación.


import java.io.*; // BufferedReader, PrintWriter, FileInputStream, File
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import es.provincia.organismo.corporativas.atlas.vo.AgendaVO;
import es.provincia.organismo.atlas.vo.AnuncioVO;
import es.provincia.organismo.atlas.vo.OrganigramaVO;


1.2.1.4. Declaraciones de clases e interfaces

La siguiente tabla describe los elementos que componen la declaración de una clase o interfaz, así como el orden en el que deben estar situados.

Elementos de declaración de una clase / interfazDescripción
Comentario de documentación de la clase/interfaz /** ... */Permite describir la clase/interfaz desarrollada. Necesario para generar la documentación de la api mediante javadoc.
Sentencia class / interface
Comentario de implementación de la clase/interfaz, si es necesario /* ... */Este comentario incluye cualquier información que no pueda incluirse en el comentario de documentación de la clase/interfaz.
Variables de clase (estáticas)En primer lugar las variables de clase públicas (public), después las protegidas (protected), posteriormente las de nivel de paquete (sin modificador), y por último las privadas (private).
Variables de instanciaPrimero las públicas (public), después las protegidas (protected), luego las de nivel de paquete (sin modificador), y finalmente las privadas (private).
Constructores
MétodosDeben agruparse por funcionalidad en lugar de agruparse por ámbito o accesibilidad. Por ejemplo, un método privado puede estar situado entre dos métodos públicos. El objetivo es desarrollar código fácil de leer y comprender.


1.3. Sangría

Como norma general se establecen 4 caracteres como unidad de sangría. Los entornos de desarrollo integrado (IDE) más populares, tales como Eclipse o NetBeans, incluyen facilidades para formatear código Java.

1.3.1. Longitud de línea

La longitud de línea no debe superar los 80 caracteres por motivos de visualización e impresión.

1.3.2. División de líneas

Cuando una expresión ocupe más de una línea, esta se podrá romper o dividir en función de los siguientes criterios,


  • Tras una coma.

  • Antes de un operador.

  • Se recomienda las rupturas de nivel superior a las de nivel inferior.

  • Alinear la nueva línea con el inicio de la expresión al mismo nivel que la línea anterior.

  • Si las reglas anteriores generan código poco comprensible, entonces estableceremos tabulaciones de 8 espacios.



Ejemplos:


unMetodo(expresionLarga1, expresionLarga 2, expresionLarga 3, 
        expresionLarga 4, expresionLarga 5);

if ((condicion1 && condicion2)
        || (condicion3 && condicion4)
        ||!(condicion5 && condicion6)) {
    unMetodo();
}


1.4. Comentarios

Distinguimos dos tipos de comentarios: los comentarios de implementación y los de documentación. 

1.4.1. Comentarios de implementación

Estos comentarios se utilizan para describir el código ("el cómo"), y en ellos se incluye información relacionada con la implementación, tales como descripción de la función de variables locales, fases lógicas de ejecución de un método, captura de excepciones, etc.

Distinguimos tres tipos de comentarios de implementación:


  • Comentarios de bloque:

    Permiten la descripción de ficheros, clases, bloques, estructuras de datos y algoritmos.
    
    /*
     * Esto es un comentario
     * de bloque
     */


  • Comentarios de línea:

    Son comentarios cortos localizados en una sola línea y tabulados al mismo nivel que el código que describen. Si ocupa más de una línea se utilizará un comentario de bloque. Deben estar precedidos por una línea en blanco.
    
    /* Esto es un comentario de línea */
    
    // Esto es otro comentario de línea


  • Comentario a final de línea

    Comentario situado al final de una sentencia de código y en la misma línea.
    
    int contador = 4 + 10;  // Inicialización del contador
    contador++;   /* Incrementamos el contador */




1.4.2. Comentarios de documentación

Los comentarios de documentación, también denominados "comentarios javadoc", se utilizan para describir la especificación del código, desde un punto de vista independiente de la implementación, de forma que pueda ser consultada por desarrolladores que probablemente no tengan acceso al código fuente.

El apartado 2 de este documento describe el uso de comentarios de documentación.


1.5. Declaraciones

1.5.1. Una declaración por línea

Se recomienda el uso de una declaración por línea, promoviendo así el uso de comentarios. Ejemplo, 


int idUnidad;   // Identificador de la unidad organizativa
String[] funciones; // Funciones de la unidad


1.5.2. Inicialización

Toda variable local tendrá que ser inicializada en el momento de su declaración, salvo que su valor inicial dependa de algún valor que tenga que ser calculado previamente.


int idUnidad = 1;
String[] funciones = { "Administración", "Intervención", "Gestión" };


1.5.3. Localización

Las declaraciones deben situarse al principio de cada bloque principal en el que se utilicen, y nunca en el momento de su uso. 


public void unMetodo() {
 int contador = 0;  // inicio del método

 ...
}


La única excepción a esta regla son los índices de los bucles "for", ya que, en Java, pueden incluirse dentro de la propia sentencia "for".


for (int i=0; contador<10; i++) {
 ...
}

Se debe evitar el uso de declaraciones que oculten a otras declaraciones de ámbito superior. 


int contador = 0;  // Inicio del método

public void unMetodo() {
 
 if (condicion) {
  int contador = 2;  // ¡¡ EVITAR !!
  ...
 }
 ...
}


1.5.4. Declaración de clases / interfaces

Durante el desarrollo de clases / interfaces se deben seguir las siguientes reglas de formateo:


  • No incluir ningún espacio entre el nombre del método y el paréntesis inicial del listado de parámetros.

  • El carácter inicio de bloque ("{") debe aparecer al final de la línea que contiene la sentencia de declaración.

  • El carácter fin de bloque ("}") se sitúa en una nueva línea tabulada al mismo nivel que su correspondiente sentencia de inicio de bloque, excepto cuando la sentencia sea nula, en tal caso se situará detrás de "{".

  • Los métodos se separarán entre sí mediante una línea en blanco.



public classe ClaseEjemplo extends Object {

 int variable1;
 int variable2;
 
 public ClaseEjemplo() {
  variable1 = 0;
  variable2 = 1;
 }
 ...
}


1.6. Sentencias

Cada línea debe contener como máximo una sentencia. Ejemplo,


int contador++;
int variable--;


Las sentencias pertenecientes a un bloque de código estarán tabuladas un nivel más a la derecha con respecto a la sentencia que las contiene.

El carácter inicio de bloque "{" debe situarse al final de la línea que inicia el bloque. El carácter final de bloque "}" debe situarse en una nueva línea tras la última línea del bloque y alineada con respecto al primer carácter de dicho bloque.

Todas la sentencias de un bloque deben encerrarse entre llaves "{ ... }", aunque el bloque conste de una única sentencia. Esta práctica permite añadir código sin cometer errores accidentalmente al olvidar añadir las llaves. Ejemplo,


if (condicion) {
 variable++;
}


La sentencia "try/catch" siempre debe tener el formato siguiente,


try {
    sentencias;
} catch (ClaseException e) {
    sentencias;
}


En el bloque "catch" siempre se imprimirá una traza de error indicando el tipo de excepción generada y posteriormente se elevará dicha excepción al código invocante, salvo que la lógica de ejecución de la aplicación no lo requiera.

Siempre se utilizará el bloque "finally" para liberar recursos y para imprimir trazas de monitorización de fin de ejecución.


try {
    sentencias;
} catch (ClaseException e) {
    sentencias;
} finally {
    sentencias;
}



1.7. Espacios en blanco

Las líneas y espacios en blanco mejoran la legibilidad del código permitiendo identificar las secciones de código relacionadas lógicamente.

Se utilizarán espacios en blanco en los siguientes casos:

Entre una palabra clave y un paréntesis. Esto permite que se distingan las llamadas a métodos de las palabras clave. Por ejemplo:


while (true) {
    ...
}


Tras cada coma en un listado de argumentos. Por ejemplo:


objeto.unMetodo(a, b, c); 


Para separar un operador binario de sus operandos, excepto en el caso del operador ("."). Nunca se utilizarán espacios entre los operadores unarios (p.e., "++" o "--") y sus operandos. Por ejemplo:


a += b + c;

a = (a + b) / (c + d);

contador++;


Para separar las expresiones incluidas en la sentencia "for". Por ejemplo:


for (expresion1; expresion2; expresion3)



Al realizar el moldeo o "casting" de clases. Ejemplo:


Unidad unidad = (Unidad) objeto;


1.8. Nomenclatura de identificadores

Las convenciones de nombres de identificadores permiten que los programas sean más fáciles de leer y por tanto más comprensibles. También proporcionan información sobre la función que desempeña el identificador dentro del código, es decir, si es una constante, una variable, una clase o un paquete, entre otros.

1.8.1. Paquetes

Se escribirán siempre en letras minúsculas para evitar que entren en conflicto con los nombres de clases o interfaces. El prefijo del paquete siempre corresponderá a un nombre de dominio de primer nivel, tal como: es, eu, org, com, net, etc. 

El resto de componentes del paquete se nombrarán de acuerdo a las normas internas de organización de la empresa: departamento, proyecto, máquina, sección, organismo, área, etc.

Generalmente se suele utilizar el nombre de dominio de Internet en orden inverso. Cuando dicho nombre contenga un carácter "-", este se sustituirá por el carácter "_".

Ejemplos:


es.provincia.organismo1.festivaldecine
es.provincia.organismo2.vivienda
es.provincia.organismo3.juventud
es.provincia.organismo3.formacion
es.provincia.organismo3.gestionturistica

java.util.ArrayList
java.util.Date
java.util.Properties

javax.servlet.http.HttpServletRequest
javax.servlet.http.HttpServletResponse


1.8.2. Clases e interfaces

Los nombres de clases deben ser sustantivos y deben tener la primera letra en mayúsculas. Si el nombre es compuesto, cada palabra componente deberá comenzar con maýusculas.
Los nombres serán simples y descriptivos. Debe evitarse el uso de acrónimos o abreviaturas, salvo en aquellos casos en los que dicha abreviatura sea más utilizada que la palabra que representa (URL, HTTP, etc.).

Las interfaces se nombrarán siguiendo los mismos criterios que los indicados para las clases. Como norma general toda interfaz se nombrará con el prefijo "I" para diferenciarla de la clase que la implementa (que tendrá el mismo nombre sin el prefijo "I").


class Ciudadano
class OrganigramaDAO
class AgendaService
class IAgendaService


1.8.3. Métodos

Los métodos deben ser verbos escritos en minúsculas. Cuando el método esté compuesto por varias palabras cada una de ellas tendrá la primera letra en mayúsculas.


public void insertaUnidad(Unidad unidad);
public void eliminaAgenda(Agenda agenda);
public void actualizaTramite(Tramite tramite)


1.8.4. Variables

Las variables se escribirán siempre en minúsculas. Las variables compuestas tendrán la primera letra de cada palabra componente en mayúsculas.

Las variables nunca podrán comenzar con el carácter "_" o "$". Los nombres de variables deben ser cortos y sus significados tienen que expresar con suficiente claridad la función que desempeñan en el código. Debe evitarse el uso de nombres de variables con un sólo carácter, excepto para variables temporales. 


Unidad unidad;
Agenda agenda;
Tramite tramite;


1.8.5. Constantes

Todos los nombres de constantes tendrán que escribirse en mayúsculas. Cuando los nombres de constantes sean compuestos las palabras se separarán entre sí mediante el carácter de subrayado "_".


int LONGITUD_MAXIMA;
int LONGITUD_MINIMA;


1.9. Prácticas de programación

1.9.1. Visibilidad de atributos de instancia y de clase

Los atributos de instancia y de clase serán siempre privados, excepto cuando tengan que ser visibles en subclases herederas, en tales casos serán declarados como protegidos.

El acceso a los atributos de una clase se realizará por medio de los métodos "get" y "set" correspondientes, incluso cuando el acceso a dichos atributos se realice en los métodos miembros de la clase.


public class Unidad {

 private int id;
 private String nombre;
 ...

 public void actualizaUnidad(Unidad unidad) {
  this.setId(unidad.getId());
  this.setNombre(unidad.getNombre());
 }

 ...
}


1.9.2. Referencias a miembros de una clase

Evitar el uso de objetos para acceder a los miembros de una clase (atributos y métodos estáticos). Utilizaremos en su lugar el nombre de la clase. Por ejemplo:


metodoUtilidad();    // Acceso desde la propia clase estática
ClaseUtilidad.metodoUtilidad(); // Acceso común desde cualquier clase


1.9.3. Constantes

Los valores constantes (literales) nunca aparecerán directamente en el código. Para designar dichos valores se utilizarán constantes escritas en mayúsculas y se declararán, según su ámbito de uso, o bien en una Clase de constantes creada para tal efecto, o bien en la clase donde sean utilizadas.


// Uso incorrecto
codigoErrorUsuarioNoEncontrado = 1;
...
switch (error) {
  case codigoErrorUsuarioNoEncontrado:
   ...
}

// Uso correcto
public final int CODIGOERROR_USUARIONOENCONTRADO = 1;
...
switch (error) {
  case CODIDOGERROR_USUARIONOENCONTRADO:
   ...
}


1.9.4. Asignación sobre variables

Se deben evitar las asignaciones de un mismo valor sobre múltiples variables en una misma sentencia, ya que dichas sentencias suelen ser difíciles de leer.


int a = b = c = 2;  // Evitar


No utilizar el operador de asignación en aquellos lugares donde sea susceptible de confusión con el operador de igualdad. Por ejemplo:


// INCORRECTO
if ((c = d++) == 0) { }

// CORRECTO
c = d++;
if (c == 0) { }


No utilizar asignaciones embebidas o anidadas. Ejemplo:


c = (c = 3) + 4 + d;  // Evitar


debería escribirse


c = 3;
c = c + 4 + d; 



1.9.5. Otras prácticas


  • Paréntesis

    Es una buena práctica el uso de paréntesis en expresiones que incluyan distintos tipos de operadores para evitar problemas de precedencia de operadores. Aunque la precedencia de operadores nos pueda parecer clara, debemos asumir que otros programadores no tengan un conocimiento exhaustivo sobre las reglas de precedencia.
    
    if (w == x && y == z)     // INCORRECTO
    if ((w == x) && (y == z)) // CORRECTO


  • Valores de retorno

    Los valores de retorno tendrán que ser simples y comprensibles, de acuerdo al propósito y comportamiento del objeto en el que se utilicen.
    
    // INCORRECTO
    public boolean esProgramador(Empleado emp) {
    
     if (emp.getRol().equals(ROL_PROGRAMADOR)) {
      return true;
     } else {
      return false;
     }
    
    }
    
    // CORRECTO
    public boolean esProgramador(Empleado emp) {
    
     boolean esUnProgramador = false;
    
     if (emp.getRol().equals(ROL_PROGRAMADOR)) {
      esUnProgramador = true;
     }
    
     return esUnProgramador;
    }


  • Expresiones en el operador condicional ternario

    Toda expresión compuesta, por uno o más operadores binarios, situada en la parte condicional del operador ternario deberá ir entre paréntesis. Ejemplo:
    
    (x >= y) ? x : y;


  • Comentarios especiales (TODO, FIXME, XXX)

    Utilizaremos XXX para comentar aquella porción de código que, aunque no tenga mal funcionamiento, requiera modificaciones. Usaremos FIXME para señalar un bloque de código erróneo que no funciona. Emplearemos TODO para comentar posibles mejoras de código, como puedan ser las debidas a optimizaciones, actualizaciones o refactorizaciones.




2. Documentación: javadoc

Se aconseja, como buena práctica de programación, incluir en la entrega de la aplicación la documentación de los ficheros fuente de todas las clases. Dicha documentación será generada por la herramienta "javadoc".

La herramienta "javadoc" construirá la documentación a partir de los comentarios (incluidos en las clases) encerrados entre los caracteres "/**" y "*/". Distinguimos tres tipos de comentarios javadoc, en función del elemento al que preceden: de clase, de variable y de método.

Dentro de los comentarios "javadoc" podremos incluir código html y etiquetas especiales de documentación. Estas etiquetas de documentación comienzan con el símbolo "@", se sitúan al inicio de línea del comentario y nos permiten incluir información específica de nuestra aplicación de una forma estándar.

Como norma general utilizaremos las siguientes etiquetas:


  • @author Nombre

    Añade información sobre el autor o autores del código.

  • @version InformacionVersion

    Permite incluir información sobre la versión y fecha del código.

  • @param NombreParametro Descripción

    Inserta el parámetro especificado y su descripción en la sección "Parameters:" de la documentación del método en el que se incluya. Estas etiquetas deben aparecer en el mismo orden en el que aparezcan los parámetros especificados del método. Este tag no puede utilizarse en comentarios de clase, interfaz o campo. Las descripciones deben ser breves.

  • @return Descripción

    Inserta la descripción indicada en la sección "Returns:" de la documentación del método. Este tag debe aparecer en los comentarios de documentación de todos los métodos, salvo en los constructores y en aquellos que no devuelvan ningún valor (void).

  • @throws NombreClase Descripción

    Añade el bloque de comentario "Throws:" incluyendo el nombre y la descripción de la excepción especificada. Todo comentario de documentación de un método debe contener un tag "@throws" por cada una de las excepciones que pueda elevar. La descripción de la excepción puede ser tan corta o larga como sea necesario y debe explicar el motivo o motivos que la originan.

  • @see Referencia

    Permite incluir en la documentación la sección de comentario "See also:", conteniendo la referencia indicada. Puede aparecer en cualquier tipo de comentario "javadoc". Nos permite hacer referencias a la documentación de otras clases o métodos.

  • @deprecated Explicación

    Esta etiqueta indica que la clase, interfaz, método o campo está obsoleto y que no debe utilizarse, y que dicho elemento posiblemente desaparecerá en futuras versiones. "javadoc" añade el comentario "Deprecated" en la documentación e incluye el texto explicativo indicado tras la etiqueta. Dicho texto debería incluir una sugerencia o referencia sobre la clase o método sustituto del elemento "deprecado".

  • @since Version

    Se utiliza para especificar cuando se ha añadido a la API la clase, interfaz, método o campo. Debería incluirse el número de versión u otro tipo de información.


El siguiente ejemplo muestra los tres tipos de comentarios "javadoc",


/**
 * UnidadOrganizativa.java:
 * 
 *  Clase que muestra ejemplos de comentarios de documentación de código. 
 * 
 * @author jlflorido
 * @version 1.0, 05/08/2008
 * @see documento "Normas de programación v1.0"
 * @since jdk 5.0 
 */
public class UnidadOrganizativa extends PoolDAO {

    /** Trazas de la aplicación */
    private Logger log = Logger.getLogger(UnidadOrganizativa.class);

    /** Identificador de la unidad organizativa */
    private int id;
 
    /** Nombre de la unidad organizativa */
    private String nombre;

    /** Obtiene el identificador de esta unidad organizativa */
    public int getId() {
        return id;
    }

    /** Establece el identificador de esta unidad organizativa */
    public void setId(int id) {
        this.id = id;
    }
 
    /** Obtiene el nombre de esta unidad organizativa */
    public String getNombre() {
        return nombre;
    }

    /** Establece el nombre de esta unidad organizativa */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    /**
     * Inserta la unidad organizativa en el sistema.
     * 
     * @param unidad Unidad organizativa a insertar
     * @throws Exception Excepción elevada durante el proceso de inserción
     */
    public void insertarUnidad(UnidadOrganizativa unidad) throws Exception{
  
        log.debug("-> insertarUnidad(UnidadOrganizativa unidad)");
  
        Connection conn = null;
        PreparedStatement pstmt = null;
        StringBuffer sqlSb = null;
  
        try {
            conn = this.dameConexion();
      
            sqlSb = new StringBuffer("")
            .append("INSERT INTO ORG.UNIDAD_ORGANIZATIVA ")
            .append("(ID, NOMBRE) VALUES (?, ?)");
      
            pstmt = conn.prepareStatement(sqlSb.toString());
            pstmt.setInt(1, unidad.getId());
            pstmt.setString(2, unidad.getNombre());
            pstmt.executeUpdate();
   
        } catch (Exception e) {

            log.error("Error: error al insertar la unidad. " +
            "Descripción:" + e.getMessage(), e);

            throw e;

        } finally {

            log.debug("<- insertarUnidad(UnidadOrganizativa unidad)");

        }
    }
}


La documentación generada por "javadoc" será la siguiente:

a) Página índice de toda la documentación generada:




b) Documentación de la clase "UnidadOrganizativa.java":








Fuente: http://javafoundations.blogspot.com.es/2010/07/java-estandares-de-programacion.html#1_8_nomenclatura

Análisis Destinty PS4 Xbox ONE - Jabato Games

Pues después de tanto "hype" sobre el juego y viendo la oferta que había en carrefour que si lo comprabas el día 9 de Septiembre te daban un cheque regalo por valor de 12 €, me decidí a comprarlo. Decir que el juego me ha salido por 48 €.

Después de 2 días probando el juego he llegado a la conclusión que ni es tan bueno como nos han querido vender ni tan malo como comentan algunos usuarios en la red. Eso sí, se tenemos en cuenta que han tardado en desarrollarlo más de 5 años y que han invertido 500 millones de dólares, creo que hay juegos con menos presupuesto que tienen un potencial parecido.



Entrando en la temática del juego se podría describir como un "Borderlands Social". Que ¿qué es eso? Pues una mezcla de juegos como Halo + Borderlands + MMO que no me llega del todo a convencer.

En el juego escoges una clase y una raza (entre 3 posibles), que nada influye en la historia del juego. Luego personalizas a tu personaje con muy poca variedad y entras en el juego. Durante tu periplo deberás ir recorriendo los planetas del Sistema Solar haciendo misiones, pero no os engañéis, el mapa de todas las misiones de cada mundo es el mismo. Increíble ¿no? sólo que en cada misión deberemos de realizar una serie de tareas que en todo momento nos las indicará nuestro espectro, ese robot que nos sigue y nos habla por todas partes, haciendo que el camino del juego sea más que lineal, careciendo de exploración.

La historia principal dura en torno a unas 11 horas, no siendo muy rejugable. Eso sí, tiene un online competitivo muy parecido al Halo.

Creo que la idea del juego es que sea infinito, es decir, a parte de las 11 horas que dura la campaña, se irán sucediendo una serie de eventos y quest para realizar en grupo con lo que alargarla la vida del juego.
Para mí la nota que merece este título es de 8.5
En resumen, es un muy buen juego, divertido y con un gran atractivo visual, que apuesta por un nuevo modo de juego online en consolas. Pero que no llega a la altura del hype que ha generado.

Detallando ahora sus pros y contras.

PROS


  • Muy buen diseño visual.
  • Gran banda sonora.
  • Excelente control y jugabilidad.
  • Posibilidad de tener una duración ilimitada.
  • Los eventos.
  • La interacción social.
  • Luz y sombras dinámicas.


CONTRAS


  • Poca personalización de los personajes, armas, etc...
  • Nula exploración.
  • No se puede interactuar con ningún elemento del entorno.
  • Horrible matchmaking.
  • Altos tiempos de carga.
  • Pobre interfaz del menú.
  • Las voces en español carecen de expresividad.
  • Cambio de primera a tercera persona en algunos momentos no me convence.
  • Campaña algo corta.
  • Mapas y misiones repetitivos.

Comentar que os ha parecido.

Saludos, by WaitSignal.

SOLUCIONADO. Fallo PS4 Expulsa continuamente el Disco DVD BlueRay. Error Ps4. Botón Expulsión. Taco de Goma.

Hay un problema de fábrica en ps4 (entre otros) que consiste en que expulsa el disco constantemente y no deja meterlo de nuevo a menos que se apague y se encienda de nuevo.

Encontré la solución al momento, lo explico por aqui por si alguien tiene el problema y no sabe que hacer.  El problema es un fallo que tienen todas las unidades, solo a a algunas les puede pasar antes y a otras después, por eso no la llevé a descambiar y lo solucioné yo mismo. 

Como podéis ver el botón no me mueve apenas cuando lo pulsas, mucha gente piensa que es táctil, pero es de presión ultrasensible (un fallo por parte de sony).  El problema residen en el taco de goma que hay debajo del botón ya que hace contacto con la esquina y se queda constantemente pulsado.  SOLUCIÓN: el taco se puede quitar y poner sin problema, puedes hacer dos cosas quitarlo y poner una pieza de goma de lo que quieras para que haga de soporte; o como yo hice separar el taco lo suficiente dejando un espacio de aire entre la goma y la play, asi nos aseguramos de que no pulse el botón y no le quitas piezas que siempre queda feo.

Conectar el mando de ps4 en ps3 inalámbricamente por bluetooth

Buenas,

pues desde la última actualización del firmware de la ps3, ya se puede jugar inalámbricamente con el mando de ps4 en ps3.

 En el siguiente vídeo viene como hacerlo.

Vídeo Conectar Mando PS4 en PS3 por Bluetooth

Saludos.

Solucionado. No se puede encontrar las rutinas de instalación para el controlador ODBC Driver de Microsoft …. Por favor vuelva a instalar el controlador.

Este problema me surgió al intentar crear un controlador ODBC para una base access en Windows Seven, en su versión de 64 bits.
Al intentar crear el controlador, se produce un error “No se puede encontrar las rutinas de instalación para el controlador ODBC Microsoft Access Driver”.

Error encontrado al crear un ODBC para Access
Lo que sucede es en definitiva que no encuentra el archivo odbcad32.exe, ya que se busca en  c:\windows\system32. La solución es, simplemente, copiarlo  al directorio c:\windows\SYSWOW64 y luego modificar el acceso directo para referenciar a dicha carpeta. Buscamos en Panel de control->Herramientas Administrativas->Orígenes de datos ODBC o en el Buscador de Inicio de windows el panel "Orígenes de datos ODBC" y no entramos, sino que hacemos click  botón derecho en él.
Si no se tienen permisos de copia en el directorio haremos lo siguiente:

Para darte permisos, en una consola (Simbolo del Sistema) arrancada en modo elevado (ejecutar como Administrador), ejecuta:
takeown /f ruta_directory_name /r /d y
icacls ruta_directory_name /grant Administrators:F /t
NOTA: si tienes Windows  en Español, en vez de administrators, debe ser Administradores. Y en la primera linea, en vez de la "y" final, debe ser una "s".

Modificación de la carpeta de destino
Luego de realizar estos pasos se puede comenzar a crear controladores ODBC para Access sin problemas.

Si no funciona, reinstala los controladores ODBC de Access. Para 32 o 64 bits. (O los 2).

http://www.microsoft.com/en-us/download/details.aspx?id=13255

Conectar a base de datos Access o MySql en Java sin DSN

Conectar a base de datos en Java sin DSN

Muchas veces para posibilitar usar nuestra aplicación java en distintos equipos, se nos hace engorroso crear DSN (Data Source Name) en todos ellos.

Hay que decir que es posible crear conexiones a base de datos desde Java sin tener que crear los nombres de orígenes de datos (DSN):

Acceso a base de datos Access desde Java sin DSN:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String myDB ="jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=c:/basedatos.mdb";
Connection conn = DriverManager.getConnection(myDB,"","");

Acceso a base de datos MySql desde Java sin DSN:
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection ("jdbc:mysql://localhost/basedatos", "usuario", "contraseña");

Una vez hecha la conexión a base de datos, podremos operar con las tablas de la misma sin tener que crear los DSN en ninguno de los equipos en los que vayamos a utilizar la aplicación.

Librerías estáticas y dinámicas Java y C en Linux

Librerías estáticas y dinámicas

Según vamos haciendo programas de ordenador, nos damos cuenta que algunas partes del código se utilizan en muchos de ellos. Por ejemplo, podemos tener varios programas que utilizan números complejos y las funciones de suma, resta, etc son comunes. También es posible, por ejemplo, que nos guste hacer juegos, y nos damos cuenta que estamos repitiendo una y otra vez el código para mover una imagen (un marcianito o a Lara Croft) por la pantalla.
Sería estupendo poder meter esas funciones en un directorio separado de los programas concretos y tenerlas ya compiladas, de forma que podamos usarlas siempre que queramos. Las ventajas enormes de esto son:
  • No tener que volver a escribir el código (o hacer copy-paste).
  • Nos ahorraremos el tiempo de compilar cada vez ese código que ya está compilado. Además, ya sabemos que mientras hacemos un programa, probamos y corregimos, hay que compilar entre muchas y "más muchas" veces.
  • El código ya compilado estará probado y será fiable. No las primeras veces, pero sí cuando ya lo hayamos usado en 200 programas distintos y le hayamos ido corrigiendo los errores.
La forma de hacer esto es hacer librerías. Una librería son una o más funciones que tenemos ya compiladas y preparadas para ser utilizadas en cualquier programa que hagamos.  Hay que tener el suficiente ojo cuando las hacemos como para no meter ninguna dependencia de algo concreto de nuestro programa. Por ejemplo, si hacemos nuestra función de mover la imagen de Lara Croft, tendremos que hacer la función de forma que admita cualquier imagen, ya que no nos pegaría nada Lara Croft dando saltos en un juego estilo "space invaders".

Cómo tenemos que organizar nuestro código

Para poder poner nuestro código en una librería, necesitamos organizarlo de la siguiente manera:
  • Uno o más ficheros fuente .c con el código de nuestras funciones.
  • Uno o más ficheros de cabecera .h con los tipos (typedefs, structs y enums) y prototipos de las funciones que queramos que se puedan utilizar.
Como siempre, vamos a hacer un ejemplo. Los ficheros serían estos:
libreria1.h
#ifndef _LIBRERIA_1_H
#define _LIBRERIA_1_H
int suma (int a, int b);
int resta (int a, int b);
#endif
libreria1.c
int suma (int a, int b)
{
    return a+b;
}
int resta (int a, int b)
{
   return a-b;
}
Es un fichero con un par de funciones simples de suma() y resta().
Un detalle importante a tener en cuenta, son los #define del fichero de cabecera (.h). Al hacer una librería, no sabemos en qué futuros programas la vamos a utilizar ni cómo estarán organizados. Supongamos en un futuro programa que hay un fichero de cabecera fichero1.h que hace #include del nuestro. Imaginemos que hay también un fichero2.h que también hace #include del nuestro. Finalmente, con un pequeño esfuerzo más, imaginemos que hay un tercer fichero3.c que hace#include de fichero1.h y fichero2.h, es decir, más o menos lo siguiente:
fichero1.h
#include <libreria1.h>
...
fichero2.h
#include <libreria1.h>
...
fichero3.c
#include <fichero1.h>
#include <fichero2.h>
...
Cuando compilemos fichero3.c, dependiendo de lo que haya definido en libreria1.h, obtendremos un error. El problema es que al incluir fichero1.h, se define todo lo que haya en ese fichero, incluido lo de libreria1.h. Cuando se incluye fichero2.h, se vuelve a intentar definir lo contenido en libreria1.h, y se obtiene un error de que esas definiciones están definidas dos veces.
La forma de evitar este problema, es meter todas las definiciones dentro de un bloque #ifndef - #endif, con el nombre (_LIBRERIA_1_H en el ejemplo) que más nos guste y distinto para cada uno de nuestros ficheros de cabecera. Es habitual poner este nombre precedido de _, acabado en _H y que coincida con el nombre del fichero de cabecera, pero en mayúsculas.
Dentro del bloque #ifndef - #endif, hacemos un #define de ese nombre (no hace falta darle ningún valor, basta con que esté definido) y luego definimos todos nuestros tipos y prototipos de funciones.
Cuando incluyamos este fichero por primera vez, _LIBRERIA_1_H no estará definido, así que se entrará dentro del bloque #ifndef - #endif y se definirán todos los tipos y prototipos de funciones, incluido el mismo _LIBRERIA_1_H. Cuando lo incluyamos por segunda vez, _LIBRERIA_1_H ya estará definido (de la inclusión anterior), por lo que no se entrará en el bloque #ifndef - #endif, y no se redefinirá nada por segunda vez.
Es buena costumbre hacer esto con todos nuestros .h, independientemente de que sean o no para librerías. Si te fijas en algún .h del sistema verás que tienes este tipo de cosas hasta aburrir. Por ejemplo, en /usr/include/stdio.h, lo primero que hay después de los comentarios, es un #ifndef _STDIO_H.

Librerias estáticas y dinámicas

En linux podemos hacer dos tipos de librerías: estáticas y dinámicas.
Una librería estática es una librería que "se copia" en nuestro programa cuando lo compilamos. Una vez que tenemos el ejecutable de nuestro programa, la librería no sirve para nada (es un decir, sirve para otros futuros proyectos). Podríamos borrarla y nuestro programa seguiría funcionando, ya que tiene copia de todo lo que necesita. Sólo se copia aquella parte de la librería que se necesite. Por ejemplo, si la librería tiene dos funciones y nuestro programa sólo llama a una, sólo se copia esa función.
Una librería dinámica NO se copia en nuestro programa al compilarlo. Cuando tengamos nuestro ejecutable y lo estemos ejecutando, cada vez que el código necesite algo de la librería, irá a buscarlo a ésta. Si borramos la librería, nuestro programa dará un error de que no la encuentra.
 ¿Cuáles son las ventajas e inconvenientes de cada uno de estos tipos de librerías?
  • Un programa compilado con librerías estáticas es más grande, ya que se hace copia de todo lo que necesita.
  • Un programa compilado con librerías estáticas se puede llevar a otro ordenador sin necesidad de llevarse las librerías.
  • Un programa compilado con librerías estáticas es, en principio, más rápido en ejecución. Cuando llama a una función de la librería, la tiene en su código y no tiene que ir a leer el fichero de la librería dinámica para encontrar la función y ejecutarla.
  • Si cambiamos una librería estática, a los ejecutables no les afecta. Si cambiamos una dinámica, los ejecutables se ven afectados. Esto es una ventaja si hemos cambiado la librería para corregir un error (se corrige automáticamente en todos los ejecutables), pero es un inconveniente si tocar eso nos hace cambiar los ejecutables (por ejemplo, hemos añadido un parámetro más a una función de la librería, los ejecutables ya hechos dejan de funcionar).
¿Qué tipo de librería uso entonces?
Es como siempre una cuestión de compromiso entre las ventajas y los inconvenientes. Para programas no muy grandes y por simplicidad, yo suelo usar librerías estáticas. Las dinámicas están bien para programas enormes o para librerías del sistema, que como están en todos los ordenadores con linux, no es necesario andar llevándoselas de un lado a otro.
En unix las librerías estáticas suelen llamarse libnombre.a y las dinámicas libnombre.so, donde nombre es el nombre de nuestra librería.

Compilar y enlazar con librerías estáticas

Una vez que tenemos nuestro código, para conseguir una librería estática debemos realizar los siguientes pasos:
  • Obtener los ficheros objeto (.o) de todos nuestros fuentes (.c). Para ello se compilan con cc -c fuente.c -o fuente.o. La opción -c le dice al compilador que no cree un ejecutable, sino sólo un fichero objeto. Aquí pongo el compilador cc, porque es el que he usado para el ejemplo, pero puede usarse gcc, o el g++ (para C++) o uno de fortran, pascal, etc.
  • Crear la librería (.a). Para ello se usa el comando ar con los siguientes parámetros: ar -rv libnombre.a fuente1.o fuente2.o ... La opción -r le dice al comando arque tiene que insertar (o reemplazar si ya están dentro) los ficheros objeto en la librería.  La opción -v es "verbose", para que muestre información mientras está haciendo las cosas. A continuación se ponen todos los fichero objeto que deseemos. ar es en realidad un comando mucho más genérico que todo esto y sirve para empaquetar cualquier tipo de fichero (no sólo ficheros objeto). Tiene además opciones para ver qué ficheros hay dentro, borrar algunos de ellos, reemplazarlos, etc.
Hacer todo este proceso a mano cada vez puede ser un poco pesado. Lo habitual es hacer un fichero de nombre Makefile en el mismo directorio donde estén los fuentes de la librería y utilizar make para compilarla. Si no sabes de qué estoy hablando, échale un ojo a la paginilla de los makefiles. Afortunádamente, las reglas implícitas de make ya saben hacer librerías estáticas. El fichero Makefile quedaría tan sencillo como esto:
Makefile
CFLAGS=-I<path1> -I<path2> ...
libnombre.a: libnombre.a (objeto1.o ojbeto2.o ...)
 
En CLAGS debes poner tantas opciones -I<path> como directorios con ficheros .h tengas que le hagan falta a los fuente de la librería para compilar.
La librería depende de los ficheros objetos que hay dentro de ella. Eso se pone poniendo el nombre de la librería y entre paréntesis los ficheros objeto. Hay algunas verisones de make que sólo admiten un fichero objeto dentro de los paréntesis. Debe ponerse entonces
libnombre.a: libnombre.a(objeto1.o) libnombre.a(objeto2.o) ...
Ya tenemos la librería. Ahora, al compilar nuestro programa con el compilador, debemos decirle dónde están las librerías y cuales son. La orden de compilación quedaría entonces
$ cc -o miprograma miprograma.c -I<path1> -I<path2> ... -L<path1> -L<path2> ... -llibreria1 -llibreria2
Los -I<path> son para indicar dónde están los ficheros de cabecera necesarios para la compilación (tanto propios del programa como los de nuestras librerías).
Los -L<path> son para indicar los directorios en los que se encuentran las librerías.
Los -llibreria son para indicar que se debe coger esa librería. En el comando sólo ponemos "librería". El prefijo lib y la extensión .a ya la pone automáticamente el compilador.
Hay un detalle importante a tener en cuenta. Las librerías deben ponerse de forma que primero esté la de más alto nivel y al final, la de más bajo nivel. Es decir, tal cual lo tenemos en el ejemplo, libreria1 puede usar funciones de libreria2, pero no al revés. El motivo es que al compilar se van leyendo las librerías consecutivamente y cargando de cada una de ellas sólo lo necesario. Vamos a verlo con un ejemplo
Supongamos que miprograma.o llama a la funcion1 de libreria1 y esta funcion1 llama a funcion2 de libreria2. El compilador lee miprograma.o. Como este necesita funcion1, la apunta como "necesaria". Luego lee libreria1. Busca en las funciones necesarias, encuentra funcion1 y la carga. Como funcion1 llama a funcion2, apunta funcion2 como función necesaria. Luego lee libreria2 y como funcion2 es necesaria, la carga. Todo correcto.
Supongamos ahora que le hemos dado la vuelta al orden, que hemos puesto -llibreria2 antes que -llibreria1. El compilador lee miprograma.c. Como este necesita funcion1, se apunta como "necesaria". Luego lee libreria2. Como funcion1 no es de esta libreria y no hay más funciones "necesarias" (hasta ahora), ignora libreria2 y no carga nada de ella. Luego lee libreria1, carga funcion1 y ve que esta necesita funcion2. Apunta funcion2 como necesaria pero ... ya se han acabado las librerias. Se obitiene un error de "linkado" en el que dice que "no encuentro funcion2".
Esto nos dice también que tenemos que tener un cierto orden a la hora de diseñar librerías. Debemos hacerlas teniendo muy claro que unas pueden llamar a otras, pero no las otras a las unas, es decir, organizarlas como en un arbol. Las de arriba pueden llamar a funciones de las de abajo, pero no al revés.
Existe una pequeña trampa, pero no es muy elegante. Consiste en poner la misma librería varias veces en varias posiciones. Si en el supuesto que no funcionaba hubiesemos puesto otra vez al final -llibreria2, habría compilado.

Compilar y "enlazar" con librerías dinámicas

Para compilar los mismos ficheros, pero como librería dinámica, tenemos que seguir los siguientes pasos:
  • Compilar los fuentes, igual que antes, para obtener los objetos.
  • Crear la librería con el comando ld. Las opciones para este comando serían ld -o liblibreria.so objeto1.o objeto2.o ... -shared. La opción -o liblibreria.so le indica el nombre que queremos dar a la librería. La opción -shared le indica que debe hacer una librería y no un ejecutable (opción por defecto). objeto1.o, objeto2.o ... son los ficheros objeto que queremos meter en la librería.
Igual que antes, hacer esto a mano puede ser pesado y se suele hacer un Makefile para compilar con make. Al igual que antes, si no sabes de que estoy hablando, ahí tienes la paginilla de los makes. Desgraciadamente, las reglas implícitas no saben hacer librerías dinámicas (o, al menos, yo no he visto cómo), así que tenemos que trabajar un poco más en el Makefile. Quedaría algo así como:
 
Makefile
liblibreria.so: objeto1.c objeto2.c ...
   cc -c -o objeto1.o objeto1.c
   cc -c -o objeto2.o objeto2.c
   ...
   ld -o liblibreria.so objeto1.o objeto2.o ... -shared
   rm objeto1.o objeto2.o ...
La librería depende de los fuentes. Se compilan para obtener los .o (habría que añadir además las opciones -I<path> que fueran necesarias), se construye la librería con ld y se borran los objetos generados. He hecho depender la librería de los fuentes para que se compile sólo si se cambia un fuente. Si la hago depender de los objetos, como al final los borro, siempre se recompilaría la librería.
El comando ld es más específico que ar, y no he encontrado opciones para modificar o borrar los objetos que hay dentro de la librería. No queda más remedio que construir la librería entera cada vez que se modifique algo.
Una vez generada la librería, para enlazar con ella nuestro programa, hay que poner:
cc -o miprograma miprograma.c -I<path1> -I<path2> ... -L<path1> -L<path2> ...  -Bdynamic -llibreria1 -llibreria2
El comando es igual que el anterior de las librerías estáticas con la excepción del -Bdynamic. Es bastante habitual generar los dos tipos de librería simultáneamente, con lo que es bastante normal encontrar de una misma librería su versión estática y su versión dinámica. Al compilar sin opción -Bdynamic puden pasar varias cosas:
  • Existen liblibreria.a y liblibreria.so. Se coge por defecto liblibreria.a
  • Sólo existe una de ellas. Se coge la que existe.
  • No existe ninguna de ellas. Error.
La opción -Bdynamic cambia el primer caso, haciendo que se coja liblibreria.so en vez de liblibreria.a. La opción -Bdynamic afecta a todas las librerías que van detrán en la línea de compilación. Para volver a cambiar, podemos poner -Bstatic en cualquier momento.
Una vez compilado el ejecutable, nos falta un último paso. Hay que decirle al programa, mientras se está ejecutando, dónde están las librerías dinámicas, puesto que las va a ir a buscar cada vez que se llame a una función de ellas. Tenemos que definir la variable de entorno LD_LIBRARY_PATH, en la que ponemos todos los directorios donde haya librerías dinámicas de interés.
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<path1>:<path2>:<path3>
$ export LD_LIBRARY_PATH
Siendo <path> los directorios en los que están las librerías dinámicas. Se ha puesto el $LD_LIBRARY_PATH pata mantener su valor anterior y añadirle los nuevos directorios.
¿Te acuerdas del ejemplo del principio con la suma?. Aquí están todos los fuentes para que puedas jugar con ellos.
  • suma.cresta.c y libreria1.h son los fuentes para la librería. Descárgalos y quítales la extensión .txt
  • principal.c es el fuente para el programa principal que usa las funciones de la librería. Descárgalo y quítale la extensión .txt
  • Makefile es un Makefile para generar todo. Descárgalo y quítale la extensión .txt. Si haces make p1, se generará la librería estática y se compilara principal.c con la librería estática para generar un ejecutable p1. Si haces make p2, se generará la librería dinámica y se compilará principal.c con la librería dinámica para generar un ejecutable p2.
    Si ejecutas ./p2 a pelo no funcionará. Acuérdate de poner el directorio actual (en el que se supone está la librería dinámica) en la variable de entorno LD_LIBRARY_PATH.
    $ LD_LIBRARY_PATH=.
    $ export LD_LIBRARY_PATH
    $ ./p2
En el Makefile hay algunas cosillas que he añadido respecto a lo explicado y las comento. He puesto la opción de compilación -Wall para obtener todos los warning posibles. También hay un objetivo "clean", que sirve para borrar las librerías y los ejecutables.