Maven Multi-Project + Jetty + Eclipse + JRebel

A continuación explicamos como configurar un proyecto Maven multi-project para que utilice JRebel + Jetty + Eclipse:

1º Creamos nuestro projecto Maven multi-project

Deberíamos tener algo parecido a esto en el pom padre.

<modules>
    <module>project-domain</module>
    <module>project-service</module>
    <module>project-webapp</module>
</modules>

Ver Cómo crear un proyecto multimódulos en maven [1].

2º Configuramos el módulo de webapp para que se pueda lanzar con jetty

En el módulo del webapp añadimos el siguiente plugin de maven:

<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <version>6.1.21</version>
    <configuration>
        <!-- Establece el contexto con el que se
             va a desplegar la aplicación -->
        <contextPath>/project</contextPath>
        <!-- Es necesario para que funcione JRebel,
        evita que Jetty detecte los cambios realizados -->
        <reload>manual</reload>
     </configuration>
</plugin>

He utilizado la versión 6 de Jetty, aunque en la última versión JRebel ya soporta la versión 7 [2].

3º Configuramos el plugin de JRebel para maven

<plugin>
  <groupId>org.zeroturnaround</groupId>
  <artifactId>javarebel-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>generate-rebel-xml</id>
      <phase>process-resources</phase>
      <goals>
        <goal>generate</goal>
      </goals><
    </execution>
  </executions>
  <configuration>
    <packaging>war</packaging>
    <classpath>
      <fallback>default</fallback>
      <resources>
        <resource>
          <!-- Indicamos a JRebel donde se encuentra
               el código del dominio -->
          <directory>
            ${basedir}/../project-domain/target/classes
          </directory>
       </resource>
        <resource>
           <!-- Indicamos a JRebel donde se encuentra
                el código de los servicios -->
        <directory>
          ${basedir}/../project-service/target/classes
        </directory>
       </resource>
      </resources>
    </classpath>
  </configuration>
</plugin>

Este plugin se ejecutará en la fase anterior que el plugin de jetty, y su función es generar el fichero ‘rebel.xml’. Para poder utilizar este plugin hemos de haber añadido a nuestro proyecto o en el settings.xml el repositorio de plugins :

<pluginRepositories>
    <pluginRepository>
        <id>zt-repo</id>
        <name>Zero turnaround repo</name>
        <url>dav:http://repos.zeroturnaround.com/maven2</url>
    </pluginRepository>
</pluginRepositories>

4º Configuramos Eclipse para realizar el debug con JRebel

Configuramos el plugin de Maven para eclipse en el webapp. Esto no es obligatorio pero es conveniente para evitar problemas futuros y mejor funcionamiento del plugin.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-eclipse-plugin</artifactId>
    <version>2.5.1</version>
    <configuration>
        <projectNameTemplate>[artifactId]</projectNameTemplate>
        <wtpapplicationxml>true</wtpapplicationxml>
        <wtpmanifest>false</wtpmanifest>
        <wtpversion>2.0</wtpversion>
    </configuration>
</plugin>

Seguimos la guía que tiene JRebel para configurar Eclipse [3].

4º Configuramos Eclipse para lanzar la aplicación

En el menú de ‘External Tools Configurations’ creamos una nueva configuración con los siguientes valores:

  • Name: Nombre que ha de tener la tarea (No puede existir dos tareas o configuración con el mismo nombre).
  • Location: M2_HOME\bin\mvnDebug.bat
  • Working Directory: ${workspace_loc:/project-webapp} (Seleccionamos el módulo del webapp previamente importado el proyecto)
  • Arguments: jetty:run -noverify -javaagent:JREBEL_HOME\jrebel.jar

Nota: En mi caso las opciones ‘-noverify -javaagent:JREBEL_HOME\jrebel.jar’ las he configurado en una copia del mvnDebug.bat y lo he sustituido en la propiedad Location.

6º Lanzamos la aplicación en modo debug

Lanzamos en eclipse la configuración establecida y posteriormente creamos una ‘Debug Configuration':

Configuramos una ‘Remote Java Application’ con los siguientes valores:
  • Name: Nombre (No ha de coincidir con la configuración anterior)
  • Project: project-webapp
  • Connection Type: Standard(Socket Attach)
  • Host: localhost
  • Port: 8000 (Por defecto en mvnDebug.bat)
  • Allow termination of remote VM: marcado (Hay un bug en windows y no finaliza el proceso, hay que matarlo manualmente)

Entonces lanzamos la configuración establecida y ya tenemos nuestra aplicación corriendo con el path indicado y en el puerto 8080(por defecto). Con ello podremos modificar el código de cualquier módulo sin necesidad de realizar un mvn install, process-resources o parar/reniciar el contenedor.

[1] http://renidev.javabolivia.com/2009/11/01/application-multi-modulo-hola-mundo-con-maven/

[2] http://www.zeroturnaround.com/blog/javarebel-2-1-1-released/

[3] http://www.zeroturnaround.com/jrebel/eclipse-jrebel-tutorial/

Lunes,30 noviembre, 2009 at 22:56 Deja un comentario

Comenzando en el Software Libre

A principios de este año en GMV  nos propusimos como objetivo el contribuir con el software libre mediante el desarrollo de nuevas funcionalidades o corrección de bugs en aplicaciones que utilizamos en nuestro ecosistema software. Por ello, decidimos que dos personas se dedicaran al desarrollo de las siguientes herramientas:

  • Desarrollo de Sonar, a la cual se dedicaría Antonio Muñiz.
  • Desarrollo de Continuum, en donde participo yo.

Junto a nosotros, otro compañero (Sergio Martín) se dedicó al desarrollo de un módulo para Drupal en el que se realizaba la integración con Alfresco mediante Servicios Web.

    Pronto se empezaron a ver los frutos. Primero Antonio Muñiz(un crack) se convirtió en committer del proyecto Sonar Pluggins mediante el desarrollo de unos ‘reportes’ para los datos de Sonar. A esto le siguió Sergio(otro crack) con la publicación del módulo con la integración entre Drupal y Alfresco. Después de visto los resultados de mis compañeros yo estaba impaciente por obtener resultados, los cuales llegaron relativamente pronto.

    Tras ‘estudiar’ el código de Continuum y familiarizarme con el flujo del mismo, empecé a reportar algunos parches para corregir bugs de la interfaz gráfica, que era la parte con la que estaba más familiarizado. Tras corregir algunos bugs posteriormente empecé con el desarrollado los test funcionales, para los cuales he utilizado Selenium + TestNG. Como consecuencia del desarrollo de los test me dieron de alta como ‘contributor’. Este momento me dio mucho ánimo ya que eran los primeros frutos de mi trabajo.

    Contributor es un reconocimiento que hace Apache a aquellas personas que han contribuido en el desarrollo de una aplicación. Normalmente para incorporar código a una aplicación de Apache es necesario que estés de acuerdo con la licencia de Apache y para ello te solicitan que firmes un documento (ICLA) en el que aceptas dichas condiciones.

    Hace una semana me llegó un correo con una pero invitación para ser ‘Commiter’ de Continuum. Esto si que no me lo esperaba, me dio un subidón tremendo, como si me quitara un peso de encima. Ya había conseguido una de las metas que me había puesto para este año, y antes de lo esperado.

    Dear Jose,
    
    On behalf of the Apache Continuum PMC, I would like to extend an
    invitation for you to become a Continuum committer. If you might be
    
    interested, please be sure to review the How the ASF Works pages.

    Por mi experiencia recomiendo a todos los que se dedican al desarrollo que se involucren en al menos un proyecto de software libre, ya que aprendes mucho, y es una buena forma de evaluarte, de ver cuanto vales como desarrollador.

    Domingo,19 abril, 2009 at 13:15 4 comentarios

    Memoria PermGen y ClassLoader

    Quién no se ha encontrado alguna vez con la temida excepción ‘java.lang.OutOfMemoryError: PermGen space failure’. Esta excepción es debida a que la máquina virtual de Java(JVM) se ha quedado sin memoria PermGen.

    ¿Cómo se distribuye la memoria en la JVM?

    En la JVM podemos diferenciar entre tres tipos de memorias:

    1. Memoria de almacenamiento dinámico o memoria Heap: Esta zona de la memoria es la encargada de almacenar las instancias de los objetos creados por las aplicaciones.
    2. Memoria de almacenamiento estático o memoria PermGen: En esta zona de la memoria se almacenan las clases que han sido cargadas por la aplicación. Esta zona también es utilizada para almacenar la información para la optimización de la aplicación por parte de la JVM.Los elementos que se almacenan en esta zona de la memoria son:
      • Métodos de las clases(incluido bytecode).
      • Nombre de las clases.
      • Pool de Constantes de la JVM [1].
      • Array de Objetos y array de tipos asociados con una clase (Ej: Array de objetos con referencia a métodos).
      • Objetos internos creados por la JVM (java.lang.Object or java.lang.Exception).
      • Información utilizada para la optimización de los compiladores.
      • Cadenas ‘internas’. Éstas se almacenan para la optimización en el acceso a las mismas.
    3. Memoria dinámica nativa: Es la zona de la memoria encargada de almacenar el código de la Interfaz Nativa de Java (JNI) o la bibliotecas nativas de una aplicación y en la puesta en práctica de la JVM asignan memoria del almacenamiento dinámico nativo.

    En nuestro casos nos referiremos a la Memoria PermGen que es la que genera la excepción anteriormente indicada.

    ¿Qué puede  causar que se produzca esta excepción?

    1. Nuestra aplicación carga demasiadas clases: A la hora de cargar las clases, la JVM lo hace bajo demanda. En la práctica esto se transforma en dos posibles casos:
      • Cuando se crea un objeto relativo a una clase, es decir, llamada mediante el operador new.
      • Cuando accedemos a algún método o atributo estático de la clase.
    2. Hay que decir que una vez que una clase es cargada en el ClassLoader no será descargada del mismo y a su vez se mantendrá una referencia desde el ClassLoader a la Clase y desde la clase al ClassLoader que la ha cargado. Todo esto será almacenado en la memoria PermGen, de tal forma que conforme vamos accediendo a las diferentes clases que son utilizadas por nuestra aplicación aumentará el tamaño ocupado.
      NOTA: Este caso puede ser especialmente dado en los JSP, ya que cada uno de ellos será convertido en un fichero de una clase Servlet. Otros casos se pueden dar en algunos frameworks como Hibernate, EJB … Debido a que estos frameworks generan clases auxiliares para la optimización de los mismos.

    3. Nuestra aplicación utiliza muchas cadenas ‘internas’: String.intern [2] es una optimización de la JVM para permitir optimizar la comparación entre cadenas. La comparación carácter a carácter entre cadenas es muy lenta, por ello se Mantiene un lista de cadenas instanciadas, de tal forma que permite una comparación de identidades que es más rápida.
    4. El problema de esto es que la lista utilizada para la comparación de cadenas es establecida en la memoria PermGen y en algunos casos el tamaño de la misma puede ser demasiado elevado. Un ejemplo de este caso se da en algunos parses de XML, los cuales genera cadenas ‘internas’ muy grandes, por ello en algunos casos pueden provocar este tipo de excepción.

      Document doc = SAXParser.new().parse( cadenaXML );
    5. Fugas de Memoria(Memory Leaks): Esto se produce cuando re-desplegamos una aplicación. En los servidores de aplicaciones se suele cargar el ClassLoader de cada una de las aplicaciones que se cargan. Si cuando re-desplegamos la aplicación no se elimina de forma correcta el ClassLoader anterior, este se mantendrá en la memoria PermGen y se sumará al espacio ocupado por la nueva aplicación. Cuando re-desplegamos un par de veces la aplicación, provocará que agotemos la memoria PermGen. Este caso se encuentra perfectamente explicado aquí [3].

    ¿Cómo solucionarlo?

    Un primera opción sería modificar nuestro código para evitar el llegar a alguno de los tres posibles casos. Esta opción muchas veces no es válida debido a que dependemos de terceros o no podemos modificar el código de nuestra aplicación. La segunda opción sería modificar los parámetros de la JVM.

    A continuación detallo un conjunto de parámetros que pueden ser indicados a la JVM para paliar, en la medida de lo posible, la aparición de esta excepción:

    • Aumentar el tamaño de la memoria PermGen. Ésta suele ser la primera medida a tomar, aunque no siempre resuelve los problemas sino que los aplaza y a veces puede derivar en problemas con el colector de basura o en problemas con la escasez de memoria dinámica.
    -XX:MaxPermSize=128m

    NOTA: Por defecto el tamaño de la memoria PermGen es de 64MB.

    • En el caso de multiprocesadores podemos establecer un colector de basura concurrente, el cual puede ‘eliminar’ memoria PermGen, cosa que el colector por defecto no puede. Para ello primero cambiamos el algoritmo del colector de basura:
    -XX:+UseConcMarkSweepGC

    Habilitamos en la JVM la posibilidad de ‘eliminar’ memoria PermGen:

     -XX:+CMSPermGenSweepingEnabled
    • Las clases son un caso particular a la hora de gestionarlas en la memoria PermGen, por ello debemos indicarle a la JVM la posibilidad de permitir que descargue las clases:
    -XX:+CMSClassUnloadingEnabled

    Referencias:

    [1] http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#20080

    [2] http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()

    [3] http://rubensa.wordpress.com/2008/02/11/java-classloader-permgen-exception/

    [4] http://my.opera.com/karmazilla/blog/index.dml/tag/permgen

    Lunes,2 febrero, 2009 at 1:36 8 comentarios

    Codificación en BD (MySQL y Oracle)

    Tanto en Oracle como en MySQL permiten establecer el conjunto de caracteres que pueden ser utilizados en los datos que se almacenan, esto es conocido como el CHARACTER SET o conjunto de caracteres permitidos. En el caso de que se intente introducir un carácter que no se encuentra en este conjunto, la BD devolvería un error indicando que el carácter no es permitido en la BD.

    Este dato puede ser establecido a la hora de crear el esquema de la BD:

    CREATE DATABASE <database_name>
    USER SYS IDENTIFIED BY <password>
    USER SYSTEM IDENTIFIED BY <password>
    CHARACTER SET <character_set_name>
    NATIONAL CHARACTER SET <character_set_name>
    ...

    y

    CREATE DATABASE <database_name>
    CHARACTER SET charset_name,
    COLLATE collation_name;

    Lo ideal sería que nuestra BD soportara el mayor numero de caracteres, de esta forma evitamos una restricción desde la BD. Como solución podríamos establecer el CHARACTER SET = UTF-8, el cual permite la representación de todos los caracteres. En el caso de Oracle, no he detectado ningún problema, ya que tanto la comparación como la ordenación es correcta una vez que establecemos el CHARACTER SET = UTF-8. Los problemas surgieron a la hora de intentar lo mismo en MySQL.

    Para facilitar las pruebas, las he realizado sobre una BD creada y lo único que he ido modificando es la codificación de la tabla que utilizaba para las pruebas.

    Caso 1 (CHARACTER SET UTF-8)

    Intentamos crear una tabla con el CHARACTER SET UTF-8.

    create table test (cadena VARCHAR(10) CHARACTER SET binary);

    En este caso se permite el conjunto de caracteres UTF-8, pero a la hora de comprobar la comparación entre cadenas detectamos que no es sensible a mayúsculas/minúsculas, además de no diferenciar entre caracteres diferentes como ‘á’ y ‘a’.

    Caso 2 (CHARACTER SET binary)

    Intentamos crear una tabla con el CHARACTER SET binary. En este caso al utilizar binary, sería parecido a la utilización de UTF-8 ya que se introduciría la codificación binaria del carácter.

    create table test (cadena VARCHAR(10) CHARACTER SET binary);

    En este caso la comparación era tanto sensible a mayúsculas/minúsculas y además se diferenciaba correctamente los caracteres diferentes (á != a). Pero en este caso se producían dos problemas:

    • La información se almacenaba en binario, es decir, era la representación binaria correspondiente a los caracteres.  Ej: ef  bf  bd  41  ef  bf  bd  49  69.
    • Debido a que la ordenación es mediante la representación binaria de los caracteres, esta ordenación era incorrecta y se podía producir el siguiente caso :  á > Á > b > a > B > A

    Caso 3 (CHARACTER SET UTF-8 collate utf8_bin)

    En este caso se permite el conjunto de caracteres UTF-8 en la representación y además se indica un collation utf8_bin, el cual provocará una comparación binaria a la hora de comparar los valores y también en la ordenación.

    create table test (cadena VARCHAR(10) CHARACTER SET utf8 collate utf8_bin);

    En este caso es sensible a mayúsculas/minúsculas, diferenciaba correctamente los caracteres diferentes (á != a) y la representación de los caracteres era correcta. En este caso el único problema era que la comparación era binaria y por ello la ordenación no era correcta.

    Caso 4 (CHARACTER SET latin1 collate latin1_general_cs)

    Por último, viendo que estableciendo CHARACTER SET=UTF8 no podíamos conseguir un comportamiento parecido al conseguido en Oracle, decidimos usar un conjunto de caracteres latin1, el cual contiene los caracteres utilizados en los países de Europa del Oeste, también añadimos el collation latin1_general_cs para permitir la sensibilidad a mayúscula/minúscula.

    create table test (cadena VARCHAR(10) CHARACTER SET latin1 collate latin1_general_cs);

    En este caso conseguimos un comportamiento igual que el obtenido en Oracle, pero con la diferencia que en este caso sólo permitiremos en nuestra BD aquellos caracteres de la codificación latin1 (http://www.collation-charts.org/mysql60/mysql604.latin1_general_cs.html)

    Estas son las sentencias utilizadas a la hora de realizar las comparaciones:

    drop table if exists test;
    
    --- Aquí va el create table correspondiente
    
    --- para realizar las comparaciones
    
    INSERT INTO test VALUES ('ábecedario');
    
    INSERT INTO test VALUES ('becedario');
    
    INSERT INTO test VALUES ('abecedario');
    
    INSERT INTO test VALUES ('nodo');
    
    INSERT INTO test VALUES ('ñ');
    
    INSERT INTO test VALUES ('oca');
    
    SELECT * FROM test where cadena like 'á%';
    
    SELECT * FROM test where cadena like 'Á%';
    
    SELECT * FROM test where cadena like 'a%';
    
    SELECT * FROM test where cadena like 'ñ';
    
    SELECT * FROM test order by cadena;

    Lunes,19 enero, 2009 at 2:52 Deja un comentario

    Personalizar esquema con Hibernate

    Las anotaciones JPA junto con el plugin hbm2ddl de Hibernate, proporcionan a los desarrolladores una fácil y rápida de generar el esquema de base de datos a partir del dominio. Muchas veces debido a los restricciones de un cliente es necesario seguir unas normas para la generación de los nombres. A continuación explicaremos un conjunto de herramientas y anotaciones de las que nos podemos valer para la generación de un esquema que siga las diferentes normas para la generación del esquema.

    (más…)

    Lunes,12 enero, 2009 at 3:22 1 comentario

    JSON ¿Qué librería elegir?

    Hoy en día se ha puesto de moda el formato JSON para el intercambio de la información entre el cliente y el servidor. En la actualidad existen varias librerías para pasar transformar un objeto Java en una cadena JSON (serialización) o viceversa (deserialización). Por lo que yo he visto hasta la actualidad, ninguna de las grandes sociedades del software libre (Apache, Sun, Jboss …) tienen una librería open source para Java que nos haga de parser el formato JSON.

    Apache en tuvo una iniciativa con la creación del proyecto Noggit, pero esta iniciativa parece un poco parada, en la actualidad este proyecto sigue en el Labs de Apache, pero no tiene ningún movimiento.

    Desde la página en donde se encuentra la especificación de JSON [1] se indican las librerías más conocidas para tratar/generar información relativa al formato JSON en los diferentes lenguajes de programación. A continuación paso a comparar las librerías que en mi opinión son las dos librerías más destacables:

    FLEXJSON [2] vs JSON-lib [3]

    Funcionalidades:

    Ambas librerías permiten la serialización de objetos Java en formato JSON, de la misma forma en ambos casos se permite excluir los atributos que van a ser serializados.

    Ventajas de flexjson:

    • Permite ‘expresiones regulares’ en los excludes. Se permiten el carácter ‘.’ para navegar por los atributos de los objetos relacionados y la utilización de ‘*’ para excluir a todos los atributos.
    • Tiene dos tipos de serializacón DEEP (todos los atributos)y SHALLOW (sólo los atributos básicos directos). Esto evita tener que excluir la mayoría de las colecciones, información que frecuentemente no es enviada o es tratada de forma independiente.
    • Permite indicar los atributos que han de ser serializados o no mediante anotaciones en las clases. Por defecto todos los atributos son serializados.
    public class User {
        private String login;
        private String password; 
    
        @JSON(include=false)
        public String getPassword() { }
    }
    • Permite indicar los atributos que queremos que sean serializados, es decir, permite la utilización de includes. Esta es una funcionalidad permite modificar la anotación del dominio o el tipo de serialización utilizado. Esta funcionalidad junto con la previa exclusión de todos los atributos, nos permite indicar aquellos atributos que únicamente han de ser serializados.

    Ejmeplo:

     new JSONSerializer().exclude("*").include("atributo1.subAtributo3", "atributo2").serialize(p);
    • Por defecto tiene definido un filtro que evita el error de LazyInicialization de Hibernate, de tal manera que intenta obtener el atributo de la BD.

    Ventajas de json-lib:

    • Permite diferentes estrategias a la hora de detección de ciclos.
    • Implementan JSONRCP, es decir, permite la serialización de funciones.
    • Permite la transformación desde XML a JSON y viceversa. En el caso de que utilicemos ambos formatos, esta es una función a tener muy en cuenta.

    Ejemplo:

      // Transformación en XML.
      JSONArray json = (JSONArray) XMLSerializer.read( xml );  
      // Transformación en JSON desde XML.
      String xml = XMLSerializer.write( json );
    • Permite la deseralización, es decir, el paso de cadena JSON a un objeto Java. Esta funcionalidad actualmente está en desarrollo en la librería FLEXJSON, aunque es esperada en la versión 2.0.
    • Tiene un módulo para la integración con Groovy.

    Dependencias:

    A la hora de analizar una librería es conveniente ver las dependencias y su tamaño. Esto influirá en la memoria utilizada y en el tamaño de nuestra aplicación. Este dato a tener en cuenta, aunque no es un factor decisivo.

    En este aspecto la librería flexjson es una la librería de peso ligero, es decir, todas sus dependencias son satisfechas por la máquina virtual de Java. A esto hay que añadirle que sólo ocupa 40K.

    En el caso de la librería json-lib, son necesarias un conjunto de dependencias, lo cual hace que aumente considerablemente el tamaño (238K). Las librerías de las que depende este proyecto son:

    • jakarta commons-lang 2.4
    • jakarta commons-beanutils 1.7.0
    • jakarta commons-collections 3.2
    • jakarta commons-logging 1.1.1
    • ezmorph 1.0.6

    Eficiencia:

    Tras realizar un conjunto de pruebas para la serialización y deserialización de objetos llegué a las siguientes conclusiones:

    • En el caso de que los objetos sean simples, es decir, sólo serializamos los atributos que dependen directamente del padre se obtiene una mejora de un 6-5% en la librería flexjson.
    • En el caso en el que los objetos son complejos, es decir, hay colecciones de objetos, arrays y dependencias de objetos, obtenemos un resultado de un 20-25% de mejoras entre las diferentes serializaciones.

    Nota: Estas pruebas se hicieron sobre una máquina virtual 1.6 en linux.

    Simplicidad:

    En el caso de flexjson, la API es bastante sencilla, ya que sólo requiere conocimiento del manejo de una par de clases para la personalización de los atributos que queremos personalizar además son es bastante intuitiva. Este código es muy flexible y fácil de extender, en cambio en json-lib las cosas se complican un poco ya que para obtener unas funcionalidades parecidas a las que proporciona flexjson es necesario la declaración de filtros y complicar un poco el desarrollo, de todas formas la serialización es básica es igual de simple de utilizar que en flexjson.

    Otra ventaja es que flexjson tiene ya implementado un conjunto de filtros para procesar valores concretos (Objetos de Hibernate, Escapar etiquetas HTML, formatear las fechas).

    Otros puntos:

    • Flexjson sólo puede ser utilizada en aplicaciones que corran sobre la versión 1.5 o posterior de la máquina virtual, en cambio json-lib tiene una implementación que corre sobre la máquina virtual 1.3 y otra sobre la 1.5.
    • La configuración de json-lib por defecto tiene un fallo a la hora de procesar las cadenas con valor null, ya que las interpreta como nulas. Esto puede ser corregido mediante la definición de un filtro.
    • La comunidad de de json-lib es más amplia tiene un equipo de desarrolladores bastante nutrido, por ello sacan versiones con relativa frecuencia. En cambio flexjson es desarrollada principalmente por Charlie Hubbard aunque está abierto a nuevas sugerencias.
    • Ambos proyectos están contruidos con maven, aunque la librería json-li se encuentra en el repositorio oficial de maven.

    Conclusión:

    En mi opinión, si vas a utilizar JSONRCP, en tu aplicación usas tanto XML como JSON, o utilizas deserialización(en desarrollo para flexjson) recomendaría que utilizaras json-lib. En cualquier otro caso mi recomendación es la utilización de flexjson. Esta librería está bastante orientada al uso de EXTJS y las funcionalidades son mayores en este aspecto.

    [1] http://www.json.org

    [2] http://flexjson.sourceforge.net/

    [3] http://json-lib.sourceforge.net/

    Miércoles,7 enero, 2009 at 1:42 3 comentarios

    Borrar todas las tablas en Oracle

    En oracle no existe ningún comando (parecido a drop all tables) que permita el borrado de todas las tablas de la BD.

    Durante la fase de diseño o en los comienzos de la fase de desarrollo se produce asiduamente la creación y eliminación de las BD debido a numerosos cambios en el diseño del dominio que finalmente va a ser utilizado. Por ello habría que buscar algo parecido a drop all tables, el cual permitiera la eliminación de todas las tablas del esquema.

    A continuación propongo las siguientes alternativas:

    1.- Eliminación del esquema de BD.

    En el caso de Oracle un esquema de BD tiene que estar asociado a un usuario de BD, por lo que esto puede ser un poco duro de ejecutar. En algunos casos los desarrolladores no tienen permisos para la creación o borrado de usuarios, y puede ser un poco molesto estar todos los días molestando al DBA para que nos elimine o cree el usuario.

    DROP USER user_name CASCADE;

    Una vez eliminado el usuario tenemos que volverlo a crear el mismo usuario, por ello deberemos tener la información relativa al DBA de la Base de datos.

    2.- Eliminación mediante la modificación del script de generación de la Base de Datos.

    Hoy en día para la creación de las BD nos ayudamos de diferentes aplicaciones/frameworks que nos permiten la generación de la BD a partir del diseño del dominio. Como ejemplo podemos poner el hibernate tools, el cual crea de forma automática el esquema de BD a partir del dominio anotado o a partir de los hbm. Este mismo framework nos permite generar el código SQL que crea/elimina las tablas de la BD.

    La ejecución del script de eliminación de tablas generado por esta herramienta y ejecutarlo tiene algunos inconvenientes:

    • Si se han producido modificaciones de forma externa al hibernate tools, no funciona correctamente
    • Sólo eliminaría las tablas que han sido creadas con este plugin por lo que el resto de tablas habría que eliminarlas de forma manual
    • No permite la eliminación de sinónimos, vistas o funciones.
    • Dependemos de terceros.

    3.- Eliminación mediante un script general.

    Una alternativa a las soluciones anteriormente propuestas es la ejecución de una sentencia SELECT que nos proporcione las sentencias que hemos de ejecutar para la eliminación de las tablas relativas al usuario actual.

    SELECT 'DROP TABLE '||table_name||' CASCADE CONSTRAINTS;' FROM user_tables

    Como consecuencia de la ejecución de este select se devolverá todas las sentencias que hemos de ejecutar para eliminar las tablas del esquema actual.

    Esta sentencia la podemos hacer más compleja para permitir la eliminación de otros elementos de la Base de Datos:

    SELECT 'DROP TABLE '||table_name||' CASCADE CONSTRAINTS;' FROM user_tables UNION
    SELECT 'DROP VIEW '||VIEW_NAME||';' FROM user_views UNION
    SELECT 'DROP SEQUENCE '|| SEQUENCE_NAME||';' FROM user_sequences UNION
    SELECT 'DROP SYNONYM ' || SYNONYM_NAME ||';' FROM user_synonyms UNION
    SELECT 'DROP FUNCTION ' || OBJECT_NAME ||';' FROM user_procedures;

    Hay que tener en cuenta que a la hora de eliminar un objeto en las versiones de oracle posteriores a la 9 se generan un un registro como copia de seguridad para la posible vuelta atrás. Por ello añadimos finalmente la sentencia ‘PURGE RECYCLEBIN;’ quedando el siguiente script:

    SELECT * FROM (
    SELECT 'DROP TABLE '||table_name||' CASCADE CONSTRAINTS;' FROM user_tables UNION
    SELECT 'DROP VIEW '||VIEW_NAME||';' FROM user_views UNION
    SELECT 'DROP SEQUENCE '|| SEQUENCE_NAME||';' FROM user_sequences UNION
    SELECT 'DROP SYNONYM ' || SYNONYM_NAME ||';' FROM user_synonyms UNION
    SELECT 'DROP FUNCTION ' || OBJECT_NAME ||';' FROM user_procedures UNION
    SELECT 'PURGE RECYCLEBIN;' FROM dual)
    ORDER BY 1 ASC;

    Una vez ejecutada la sentencia, copiamos el resultado y lo ejecutamos. Como resultados obtendremos el esquema totalmente limpio.

    Para evitar tener que copiar esta sentencia en un fichero y copiarlo cada vez que queramos eliminar el esquema de BD, nos podemos ayudar del cliente que utilicemos para acceder a la BD. En mi caso suelo utilizar SQL SQUIRREL y este me permite asociar una abreviación a un script, así que sólo tengo que asociar la sentencia DROPALL a la consulta anteriormente indicada.

    Ejemplo:

    DROP SEQUENCE HIBERNATE_SEQUENCE;
    DROP SYNONYM PERSONA;
    DROP SYNONYM CIUDADES;
    DROP TABLE TABLA1 CASCADE CONSTRAINTS;
    DROP TABLE TABLA2 CASCADE CONSTRAINTS;

    Domingo,4 enero, 2009 at 1:45 6 comentarios

    Entradas antiguas


    Feeds

    Entradas Recientes


    Seguir

    Recibe cada nueva publicación en tu buzón de correo electrónico.