Contacto

Nos puedes enviar un artículo a publicar (si te fue útil, seguro que a otros también).
Nos puedes sugerir temas/profundidad de interés.
correo-e - perfil

Busquedas

Encriptar password en JBoss

 Cómo encriptar contraseñas - y usar contraseñas encriptadas - en JBoss.

 Normalmente, en las aplicaciones que realizamos para correr en jboss, es necesario conectarse a una base de datos.
 Los datos de conexión a la base, incluso la contraseña de acceso, suelen estar en un archivo de texto plano ( "datasource", -ds.xml).
 En este artículo, vamos a describir la forma de encriptar las claves usadas en los archivos datasource, por medio de bibliotecas disponibles en JBoss, y cómo configurar el acceso a la base de datos, con la contraseña encriptada desde JBoss.
 Para más información, ver la documentación de JBoss sobre JAAS, y es interesante el capítulo 5 del libro: "JBoss: A Developer's Notebook" de O'Reilly.

Configurando un datasource seguro:
 1) Ejemplo de datasource con contraseña en texto plano.
 A continuación, un archivo datasource sencillo, con la contraseña sin cifrar.
Leer más...

Ajax en java - un ejemplo con dwr

 En el artículo anterior (Ajax en java - dwr) se configuró el framework DWR en un proyecto web.
 Continuando con la introducción a dwr, vamos a ver algunas acciones que pueden ser comunes en un proyecto web, como ser:
   Ejecutar (por ajax) un método con parámetros en el servidor (esto lo hacemos usando dwr).
   Acceder a un objeto en sesión con dwr.
   Desde el servidor, retornar al cliente un array de String .
   En el cliente, cargar un combo usando funciones javascript de dwr.
  Para el ejemplo, asumimos que:
Leer más...

Ajax en java - dwr

 Ajax en java fácil usando DWR

  El objetivo de esta primera entrega, es hacer una breve introducción al framework DWR, y que esté instalado / configurado en nuestro proyecto web.

 Por medio de Ajax ( Asynchronous JavaScript and XML ), es posible transferir datos entre el el cliente (el navegador web) y el servidor en "background".
 Esto permite generar un comportamiento dinámico, sin cargar (o refrescar) todo el contenido de la pantalla. Como ejemplo sencillo, podemos imaginar un formulario en el cual hay un combo con una lista de países. Al hacer click en uno de los países, se carga otro combo con sus ciudades.
 Para esta sencilla tarea aparente, es necesario escribir 2 bloques de datos bien diferenciados:
  1) En el cliente: En javascript el código que captura la acción del usuario, envía al server los datos requeridos por esa acción, y espera la respuesta (de forma asincrónica) para generar el nuevo combo (o el comportamiento que corresponda).
  2) En el server escribir un servlet que captura la petición http, y retorne los datos al cliente.

 Bienvenido DWR
  DWR (Direct Web Remoting - http://directwebremoting.org/dwr) es un framework open source en java, que permite escribir aplicaciones AJAX, unicamente escribiendo código java en clases comunes (POJOS), sin necesidad de conocer detalles de ajax, como ser la forma de enviar objetos/datos por medio de javascript desde el cliente al servidor, la captura y lectura de la respuesta.
  De esta forma reducimos casi al mínimo el código nativo en javascript, y tampoco tenemos que escribir los servlets.
  DWR incluye un servlet principal que se tiene que configurar (funciona como controlador), y varias bibliotecas de javascrip necesarias por el propio framework, y que nos son útiles para diferentes tareas.

 Configurar dwr en pocas palabras :)
  Montar el framework en nuestros proyectos web, probablemente no podría ser mas fácil.

  Asumimos que tenemos un proyecto web (en el ejemplo se llama: "DWREjemplo"), y la biblioteca dwr.jar ( http://directwebremoting.org/dwr/download.html ).
    Nota: En los ejemplos usamos la versión estable 2.X. En el momento de escribir el artículo, está disponible también la versión 3 no estable .

 La configuración se puede hacer en dos archivos.
  En web.xml se configura el servlet que funciona como "controlador" en el framework.
  El otro archivo es dwr.xml, aquí se se indica varias configuraciones, como ser las clases java usadas y el nombre lógico con el que se accede a estas clases desde javascript (será el nombre de la libreria javascript a importar en las páginas). También se indica lo métodos a los que se puede acceder, tipos de datos personalizados...

  Básicamente, lo que hace el framework es convertir las clases java configuradas, en bibliotecas javascript. El nombre de la biblioteca es parte de la configuración que tenemos que hacer.

  1) Incluir la biblioteca de dwr al proyecto web (dwr.jar)
     Incluir las bibliotecas commons de apache ( http://commons.apache.org/ ). Algunos servidores ya incluyen estos jars. Puedes arrancar la aplicación, y si tienes algún mensaje del tipo: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory, agregar commons-logging.jar (y los jars necesarios, según los mensajes).

  2) Agregamos la configuración del servlet de dwr. Para esto agregamos el siguiente contenido en el archivo web.xml.

    <servlet>
     <servlet-name>dwr-invoker</servlet-name>
     <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
     <init-param>
       <param-name>debug</param-name>
       <param-value>true</param-value>
     </init-param>
    </servlet>
    <servlet-mapping>
     <servlet-name>dwr-invoker</servlet-name>
     <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>

 3) En WEB-INF se crea el archivo dwr.xml.
 En el primer ejemplo, vamos a configurar una clase que llamamos: SaludoAjx (en el paquete dwrjs). En esta clase vamos a tener un método público "getSaludoSimple" que retorna un String. A esta clase, desde javascript, vamos a acceder con el nombre del objeto "SaludoJS".

     WEB-INF/dwr.xml
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
  "http://getahead.org/dwr/dwr20.dtd">
  <dwr>
    <allow>
        <create creator="new" javascript="SaludoJS">
            <param name="class"
                   value="dwrjs.SaludoAjx"/>
            <include method="getSaludoSimple" />
        </create>
    </allow>
  </dwr>

 4) Creamos la clase y el método indicado en el paso anterior (la clase SaludoAjx en el paquete dwrjs, y el método getSaludoSimple)
    Esta clase tiene que tener el constructor por defecto sin argumentos.

   dwrjs.SaludoAjx.java
package dwrjs;
public class SaludoAjx {
  public String getSaludo()
    { return "Hola Mundo con DWR"; }
  }

 Ya tenemos configurado el ambiente, ahora, a probar si está funcionando.
 Ejecutamos el proyecto, y en el navegador vamos a la url: host:puerto/proyecto/dwr
 En mi caso: http://localhost:8080/DWREjemplo/dwr/index.html

 Si todo funciona bien, se nos presenta una página con las clases conocidas por DWR, en nuestro ejemplo:
   SaludoJS (dwrjs.SaludoAjx).
   Al hacer click en el link de la clase, se muestra otra página con los métodos disponibles.

   Nota: Para tener esta pantalla de test de dwr, es necesario que esté habilitado en la configuración del serlvet ( paso 2), el parámetro "debug".

 5) Vamos a crear una página sencilla, en el cuál hay un botón que, al hacer click, nos muestra el saludo (el texto desde el server)

     index.html
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <script type='text/javascript' src='/DWREjemplo/dwr/util.js'></script>
        <script type='text/javascript' src='/DWREjemplo/dwr/engine.js'></script>
        <script type='text/javascript' src='/DWREjemplo/dwr/interface/SaludoJS.js'></script>

        <script type="text/javascript">
            function cargarSaludo(){
                SaludoJS.getSaludo(setMsgSaludo); }

            function setMsgSaludo( strRetorno){
                divTxt=dwr.util.byId("txtDinamico");
                divTxt.innerHTML=strRetorno; }
        </script>
    </head>

    <body >
        <h1>Ejemplo DWR!</h1>
        <button onclick="cargarSaludo();" >Ver Saludo</button>
        <div id="txtDinamico" />
    </body>
</html>

 Descripción de la página
  a) En la etiqueta 'button', indicamos que al hacer 'click' llame a la función de javascript "cargarSaludo()"

 Dentro de la etiqueta "head"
  b) Las primeras 2 lineas cargamos bibliotecas necesarias por dwr (y nosotros)
  c) En la tercer linea importamos nuestra propia libreria SaludoJS.js
       notar la ruta de las bibliotecas, en las propias de dwr están de la forma:
          /proyecto/dwr/biblioteca.js, y las que corresponden a nuestras clases están de
          la forma:  /proyecto/dwr/interface/biblioteca.js

  d) Creamos la función de javascript "cargarSaludo()" (ejecutado al hacer "click" desde el botón).
    En nuestro caso particular, solo tenemos una línea:
          SaludoJS.getSaludo(setMsgSaludo);
    Lo que estamos haciendo es llamar en nuestra biblioteca (SaludoJS), el método que queremos ejecutar (getSaludo), y como parámetro, lo que indicamos
 es el método que se tiene que ejecutar cuando llegue la respuesta del servidor (aquí es donde aparece la "magia" de dwr, y nos abstraemos de todos los detalles de esta comunicación).
  
    En caso de que el método en nuestra clase tenga parámetros, primero se agregan los parámetros necesarios, y por último, el nombre del método a ejecutar al retorno del servidor.

 e) Se crea el método javascript "setMsgSaludo", con un parámetro, que va a contener los datos de la respuesta del servidor.
    Cuando se obtiene la respuesta del server (pto anterior), se ejecuta automáticamente este método, y se agrega como argumento la respuesta del servidor.
    En nuestro ejemplo, lo que hacemos es, al 'div' cuyo id es "txtDinamico", le agregamos directamente la respuesta del servidor.

  Como resultado, al hacer click, tendremos bajo el botón una linea con el texto: Hola Mundo con DWR

  Dejo el paquete con el proyecto de prueba (fuentes y war) bajar ejemplo DWR
  En la página oficial tienen muy buena documentación:  http://directwebremoting.org/dwr/index.html

Leer más...

Permisos en Linux

 Manejo de permisos de archivos en linux
      Todos los archivos en linux (los directorios y dispositivos también son archivos), tienen un conjunto de permisos, que determinan qué usuarios pueden acceder a estos archivos, y qué es lo que pueden realizar.
 Los permisos que se otorgan son de lectura (r), escritura (w) y ejecución (x).

 En cada archivo, estos permisos se asignan a tres categorías de usuarios, de forma independiente. Estas categorías de usuarios son:
   Propietario (owner): Es el usuario al que pertenece el archivo. Por defecto, el usuario que crea un archivo es el propietario (puede ser cambiado).
   Grupo (group): Es un conjunto de usuarios asociados a un grupo, a los cuales se les quiere asignar permisos para el archivo.
   Otros (other): Son todos los usuarios que no pertenecen a las dos categorías previas.

 Al asignar los permisos de forma independiente, permite que el propietario tenga, por ejemplo, permiso de leer y escribir un archivo, mientras que
los miembros del grupo solo pueden leerlo, y el resto de usuarios no puedan acceder.

 Para ver la información detallada de un archivo en linux, usamos el comando "ls -l". En el siguiente ejemplo, se muestra un directorio y un archivo de texto.
   drwxr-xr-x 2 dlix lectores 4096 2010-01-10 17:55 doc
   -rw-r----- 1 dlix lectores  192 2010-01-10 17:55 log.txt

 Recorriendo el resultado de 'ls -l' de izquierda a derecha, vamos a describir las diez posiciones iniciales:

1) Tipo de archivo: El primer carácter indica el tipo de archivo. Alguno de los caracteres (y su significados) posibles son:
    "-" : representa un archivo (como un txt, html, pdf)
    "d" : indica que el archivo es un directorio.
    "l" : indica que el archivo es un enlace simbólico
    "c" : indica que es un archivo especial de caractéeres (ej.ttyS0 )
    "b" : indica que es un archivo especial de bloques (ej. sda1 )

   En el ejemplo anterior, "doc" es un directorio, y "log.txt" es un archivo de texto.

 2) Los siguientes nueve carácteres representan los permisos (rwx), agrupados por la categoría de usuario.
    Los permisos no concedidos (por ejemplo, no se tiene permiso de ejecución), se representa con un guión (-).

 2.1) El primer conjunto de tres caracteres representan los permisos que se otorga al propietario (owner) del archivo.
   
    En el ejemplo, para el directorio "doc" el propietario "dlix" tiene permiso de lectura, escritura, ejecución (rwx).
    Para el archivo "log.txt", el propietario tiene permisos de lectura y escritura (rw-). No se otorgó permiso de ejecución (-).

 2.2) El segundo conjunto de tres caracteres representan los permisos otorgados al grupo (group) del archivo.
   
    En el ejemplo, para el directorio "doc", el grupo "lectores" tienen permiso de lectura y ejecución (r-x).
    Para el archivo "log.txt", el grupo "lectores" solo tiene permiso de lectura (r--).

 2.3) El tercer y último conjunto de tres caracteres representan los permisos otorgados a la categoría de otros usuarios (others).
   
    En el ejemplo, para el directorio "doc" estos 'otros' usuarios tiene permiso de lectura y ejecución (r-x).
    Para el archivo "log.txt", estos 'otros' usuarios no tienen ningún permiso (---), por lo que no pueden realizar ninguna acción.

 3) Vamos a saltear el siguiente carácter (que representa el numero de enlaces al archivo), con lo que luego tenemos el propietario y
a continuación el grupo del archivo, en nuestro ejemplo, 'dlix' y 'lectores' respectivamente.

 Permisos en Directorios
  Como se puede ver en el ejemplo, los permisos en el directorio son los mismos que en un archivo (rwx).
  Es importante comprender el significado que estos tienen en el directorio.

  El permiso de lectura en el directorio permite ver los archivos que hay en él.
  El permiso de ejecución, permite ingresar en él ( hacer 'cd ').
  El permiso de escritura, permite crear archivos en el directorio, y eliminar los propios.

 Representación de los permisos en linux
   Los permisos pueden representar de dos formas.
   Una es mediante símbolos de permisos, como se han visto hasta ahora en este artículo: r w x (lectura, escritura, ejecución).
  Otra forma es mediante código numéricos, expresado en notación octal. Este método es muy útil en el momento de modificar permisos.
  En la representación numérica:
    4  => representa el permiso de solo lectura (r).
    2  => representa el permiso de solo escritura (w).
    1  => representa el permiso de solo ejecución (x).

  Para representar combinación de permisos, se suman los códigos que están presentes.
  Por ejemplo, si se quiere representar un archivo que tiene permisos de lectura y ejecución, mediante símbolos: r-x. Mediante código numéricos,
 simplemente sería 5 ( 4 + 1 == lectura + ejecución ). Un archivo con todos los permisos (rwx) en código numérico es 7 (4 + 2 + 1  == lectura + escritura + ejecución  ).

 Modificación de Permisos en linux: comando chmod
  El comando chmod nos permite modificar los permisos de los archivos en linux.
  Los permisos se pueden representar por sus símbolos (conocido como método relativo), o mediante la codificación numérica (conocido coo método absoluto).

 Para el método relativo (o simbólico), a los símbolos ya mencionados (rwx) se tiene que agregar la siguiente lista:
  u : Agrega o elimina un permiso al propietario del archivo.
  g : Agrega o elimina un permiso al grupo del archivo.
  o : Agrega o elimina un permiso la categoría de usuarios 'otros'. (recordamos, no es el propietario, ni pertenecen al grupo).
  a : Agrega o elimina un permiso a todas las categorías de usuarios ( ugo ).
  + : Significa que se agrega el permiso.
  - : Significa que se elimine el permiso.

 El modo de empleo es, indicar la categoría de usuario al cual se quiere asignar el permiso, el símbolo +/- (agregar/eliminar), y los símbolos de los permisos.

 Algunos ejemplos:
  De acuerdo a esto, si se quiere eliminar el permiso de escritura a todos los usuarios del archivo log.txt:
      chmod a-w log.txt
  Si se quiere dar permisos de escritura y ejecución al directorio doc, para los usuarios 'otros':
      chmod o+xw doc/
  Si se quiere dar permiso para los usuarios 'otros' de lectura, y eliminar los permisos de escritura y ejecución en el archivo log:
      chmod o+r-wx log.txt

 Para asignar permisos por medio de caracteres numéricos (método absoluto), siempre se hace referencia a las tres categorías de usuario.
 Se utilizan 3 dígitos, en donde cada dígito representa los permisos (rwx) de cada categoría.
 El primer dígito corresponde a los permisos para el propietario, el segundo para el grupo, y el tercero para otros.

 Algunos ejemplos:
  Si se ejecuta el siguiente comando:  chmod 764 log.txt
   el primer dígito asigna permisos para el propietario. El 7 significa que se dan todos los permisos (rwx == 4+2+1).
   el segundo dígito asigna permisos para el grupo. El 6 significa que se da permiso de lectura y escritura (rw == 4+2).
   el tercer dígito asigna permisos para otros. El 4 significa que se da permiso de lectura (r == 4).
  Si hacemos ahora: ls -l log.txt  obtenemos:  -rwxrw-r-- 1 dlix lectura 0 2010-01-10 00:30 log.txt

 Que método usar depende de la situación, y en particular, lo que sea más cómodo de forma personal.
 Cuando se tiene que modificar los permisos de todos los grupos, el método absoluto resultaría el más cómodo. Cuando tengo que cambiar un permiso concreto para
una de las categorías de usuario, el método simbólico resulta más intuitivo.

 Aplicar modificación de permisos de forma recursiva.
   Cuando se quiere realizar cualquier modificación de permisos (como vimos en los ejemplos anteriores), de forma recursiva a todos los archivos y directorios, se usa la opción "-R".

  Por ejemplo, para dar todos los permisos al propietario, permiso de lectura y ejecución al grupo, y ningún permiso a otros, para todos los directorios y archivos dentro del directorio doc, se puede hacer mediante:
  chmod -R 750 doc  ==> Resultado:  drwxr-x---  (para el directorio doc, y todos sus subdirectorios y archivos)


Leer más...

Expresiones Regulares - Metacaracteres

 Expresiones Regulares

   Una expresión regular es un conjunto de caracteres que se lo conoce como "patrón". Por medio de aplicaciones que soporten expresiones regulares, es posible buscar o sustituir estos patrones dentro de un texto, evitando tener que escribir código específico para esa tarea.
   Si bien las expresiones regulares son una herramienta muy potente para la manipulación de texto, puede dificultar el mantenimiento y/o localización de errores, cuando se generan patrones complejos. En estos casos, la clásica recomendación ... documentar.
   Un ejemplo de patrón que suele estar en los textos que tocan el tema, es la búsqueda de un archivo desde linea de comando, por ejemplo:
     ls m*.txt  ( o en DOS:  dir m*.txt)  :  este patrón busca todos los archivos que comienzan con la letra "m", continúan con cualquier carácter, y terminan con ".txt".

 Metacaracteres en expresiones regulares:
   Algunos caracteres en una expresión regular tienen un comportamiento específico. A estos caracteres se los conoce como "metacaracteres". En la siguiente lista, se explica algunos de estos importantes caracteres, que usaremos en diferentes ejemplos:

Operador Descripción Ejemplo
\ Es el carácter de escape. Modifica el comportamiento "normal" del carácter que le sigue. Por ejemplo, si se quiere buscar el propio carácter "\", se tiene que hacer por medio de "\\"
^ Indica una coincidencia al comienzo de la cadena (ver diferencia cuando se usa con parentesis rectos) ^Linux Indica que comienza con la frase "Linux"
$ Indica una coincidencia al final de la cadena. Ubuntu$ Indica que termina con la frase "Ubuntu"
. Usado cuando se quiere representar cualquier carácter (sin incluir el salto de linea '\n').
| Funciona como el "OR" para las expresiones regulares. Coincide con la expresión en un lado u otro del carácter "|" Por ejemplo, lin(ux|terna) coincide con linux y linterna (luego veremos el metacarácter "(...)"
[ ] Se busca coincidencia con cualquier carácter incluido dentro de los paréntesis rectos. EN "Linu[xsr]" hay coincidencia con: Linux Linur Linus
[ - ] El "-" se usa para indicar un intervalo de caracteres [a-z] representa cualquier carácter alfabético en minúscula. [2-4] representa cualquier dígito entre 2 y 4.
doc[2-4] coincide con doc2 doc3 doc4
[^ ] Con "[^" se indica "clase exclusiva" o negativo. Se usa cuando el patrón de búsqueda coincide con cualquier carácter, EXCEPTO éstos. En doc[^24], NO coincide con doc4 o doc2, sí con doc3, docu . También usado con intervalos de caracteres
( ) Representa un grupo de caracteres que son tratados como una única expresión En doc(24|umentos), Coincide con doc24 y documentos (Ver que se uso el carácter "|" en el ejemplo)
Representación de caracteres que se repiten
* Indica que la expresión anterior al carácter puede repetirce cero o más veces. "ub*" indica que el carácter "b" puede no existir, por lo que va a coincidir la expresión con todas las 'u',
y si existe, coincide con todas las repeticiones de 'b' luego de una 'u'. Por lo que va a coincidir con:
ubuntu, ubbbuntu incluso solo con ucualquierCosa
+ Indica que la expresión anterior al carácter se repite una o más veces. "li+" coincide con linux , con liinux , pero no "lalgo" o "l" (tiene que estar el carácter 'i')
? Indica que la expresión anterior a éste símbolo es opcional, por lo que puede estar una sola vez, o ninguna "Linux?" coincide con Linux o con Linu
{N} Indica que se encuentra coincidencia cuando la expresión anterior se repite N veces. x{2} coincide con xx. Si indicamos sustituir x{2} por Z, en xxxx por defecto, el resultado será ZZ
{N,} Indica que se encuentra coincidencia cuando se repite como mínimo N veces (sin máximo). x{2,} coincide con xx (y todas las x que estén luego). Si indicamos sustituir x{2,} por Z, en xxxx por defecto el resultado será Z
{N,M} Indica que la expresión anterior se repite como mínimo N veces, y no más de M veces. x{2,3} coincide con xx y con xxx.
Notas: En estos casos, si N es el único valor, N >=1. En el resto de los casos, N >= 0, y si se usa M, N <= M
<patronRepetición>? Si se agrega ? luego de alguno de los cuantificadores anteriores " *, +, ?, {N}, {N,}, {N,M})", se genera una versión "lazy".
Lo que hace es coincidir con la mínima expresión posible. Este concepto es importante y suele generar confusiones con el comportamiento por defecto,
en donde la coincidencias se expanden a la mayor expresión posible.
Si en: "<b>asljlj</b> <b>tarja</b>" queremos reemplazar todo el texto que hay dentro de los
tags "<b>...</b>" por ZZ, tenemos que usar este modo "lazy", la solución sería:
"<b>.*?</b>", de esta forma coincide con el texto dentro de cada bloque, y tendríamos:
"<b>ZZ</b> <b>ZZ</b>".
Si no se usa el modo lazy ("<b>.*</b>") el comportamiento seria modificar TODO el texto desde el primer tag
"<b>" (incluso otros tags <b> y </b>) hasta llegar al último tag "</b>", con el resultado:
"<b>ZZ</b>"
A continuación un grupo de metacaracteres que representan un "atajo" en representación de patrones.
 \w   Representa a cualquier carácter alfanumérico, incluyendo el guión bajo. Equivale a [a-zA-Z0-9_]'.
 \W  Representa a cualquier carácter que no sea alfanumérico. Equivale a [^a-zA-Z0-9_] .
 \d Representa cualquier dígito. Equivale a [0-9]. doc\d es igual a doc\d
 \D Reprecenta a cualquier carácter que NO sea un dígito. Equivale a [^0-9].
 \s Coincide con cualquier carácter que represente espacio en blanco, incluido nueva línea. Equivale a [^ \n\r\f\t\v].
 \S  Representa a cualquier carácter excepto aquellos que sean espacio en blanco. Equivale a [^ \n\r\f\t\v].
Algunos caracteres de texto no imprimibles
  \n   Representa el carácter de nueva línea.
\r Representa el carácter de retorno de carro.
\t Representa el carácter de tabulación.
\v Representa el carácter de tabulación vertical.
\f Representa un salto de página.


Muchos lenguajes y programas soportan expresiones regulares, como ser java, oracle, .net, perl, entre muchos otros, con sus particularidades. Hemos visto algo en los artículos dedicados a grep y el editor vi. En próximos post veremos algunas herramientas que nos faciliten la creación y pruebas de nuestras expresiones regulares, y el uso en java.
Leer más...