tag:blogger.com,1999:blog-6424350859955129692024-02-19T02:10:59.998-03:00GetGeekTecnología Computación Ciencia Blog Geek Linux Windows Programaciónegaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-642435085995512969.post-23793680750270016512012-05-26T01:15:00.000-04:002013-01-14T23:50:42.843-03:00JDirMonitor Java File listener API (Actualizado 14/01/2013)<b>14/01/2012</b>
<br />
Se añade a la interfaz JDirMonitor métodos que permiten consultar y obtener, a través del path absoluto, archivos que se encuentren dentro del directorio que se está analizando.
<b><br />26/05/2012</b>
<br />
Se añade en clase "cl.getsoftware.jdirmonitor.task.RecursiveTaskMonitor" capacidad de informar estado tanto de los archivos como de los directorios.<br />
<br />
----------------------------------------------------------------------------------------------------------------------- <br />
<br />
<br />
Hace unos días atrás se presentó un problema en un sistema y parte de la solución que se propuso involucraba leer información escrita en tiempo real desde múltiples archivos de bytes con objetos serializados, procesarlos y delegarlos a un sistema anexo, todo esto en Java.<br />
Lo primero que se me ocurrió fue 'googlear' para encontrar una API que hiciera el trabajo de monitorear cambios en los archivos de un directorio y por alguna oscura razón no encontré nada...<br />
<span id="fullpost"><br />
Una vez solucionado el asunto me interesó la idea de crear una API lo suficientemente genérica, configurable y fácil de usar que solucionase dicho 'problema'.Y así nació JDirMonitor!<br />
<br />
Entonces JDirMonitor es una API, bajo licencia <a href="http://www.gnu.org/licenses/lgpl-2.1.html">LGPL</a> que permite monitoriar y 'escuchar' los cambios que presentan todos los archivos que estén dentro de un directorio definido, avisando en su defecto cuáles han sido creados, modificados y eliminados.<br />
<br />
Además de esto JDirMonitor posee las siguientes características:<br />
-Definición de múltiples listeners para capturar eventos que suceden sobre los archivos.<br />
-Definición de Filtros a aplicar sobre los archivos para, por ejemplo, discriminar cuáles deben procesarse.<br />
-Definición de Comparators de objetos File para, por ejemplo, definir el orden en el que se deben procesar los distintos archivos.<br />
<br />
JDirMonitor ofrece 2 tipos de monitoreos:<br />
1) NormalTaskMonitor: analiza solamente los archivos que se encuentran en el primer nivel del directorio especificado.<br />
2) RecursiveTaskMonitor: analiza todos los archivos que se encuentren dentro del directorio a analizar, es recursivo IN ORDEN, ya que accede a los archivos de todos los subdirectorios (en cualquier nivel de profundidad).<br />
<br />
El siguiente código de ejemplo permite monitorear un directorio X con NormalTaskMonitor, un listener y un filtro de archivo:<br />
<br />
<pre class="brush: java;">import java.io.File;
import java.util.concurrent.TimeUnit;
import cl.getsoftware.jdirmonitor.DirectoryMonitor;
import cl.getsoftware.jdirmonitor.MonitorBuilder;
import cl.getsoftware.jdirmonitor.exception.DirectoryMonitorException;
import cl.getsoftware.jdirmonitor.filter.RegexNameFileFilter;
import cl.getsoftware.jdirmonitor.listener.FileListener;
import cl.getsoftware.jdirmonitor.task.NormalTaskMonitor;
public class Test {
public static void main(String[] args) throws DirectoryMonitorException {
String pathDirectory = "ruta/del/directorio/a/monitorear";
long timeTaskExecute = 2;
//Clase que permite añadir filtros a archivos y directorios
//mediante expresiones regulares
RegexNameFileFilter regexName =
new RegexNameFileFilter();
regexName.addFileNameRegex("[a-zA-Z].*?\\.txt$");
MonitorBuilder builder = new MonitorBuilder(pathDirectory,
timeTaskExecute, new NormalTaskMonitor(),
TimeUnit.SECONDS);
builder.addListener(fileListener);
builder.setFileFilter( regexName );
DirectoryMonitor monitor = builder.build();
monitor.start();
//se deja el hilo main vivo en un ciclo infinito
//para ver lo que imprimen los listeners en consola
while( true ){
try {
Thread.sleep(10000);
}
catch (InterruptedException e) {}
}
}
public static FileListener fileListener = new FileListener() {
@Override
public void fileDeleted(File file) {
System.out.println("Archivo " + file.getAbsolutePath() + " ha sido BORRADO");
}
@Override
public void fileCreated(File file) {
System.out.println("Archivo " + file.getAbsolutePath() + " ha sido CREADO");
}
@Override
public void fileChanged(File file) {
System.out.println("Archivo " + file.getAbsolutePath() + " ha sido MODIFICADO");
}
};
}
</pre>
Así de simple, en 4 líneas tenemos corriendo un DirectoryMonitor que revisará el directorio periódicamente cada N segundos, nos informará a través del listener los cambios que ocurren en los archivos y con la clase cl.getsoftware.jdirmonitor.filter.RegexNameFileFilter se logra filtrar solo los archivos que posean un nombre que cumpla con la expresión regular definida.<br />
<br />
Otra ventaja es que la API te permite codificar tus propias clases de monitoreo, las cuales deben heredar de la clase cl.getsoftware.jdirmonitor.AbstractTaskMonitor.<br />
<br />
Por ejemplo, este es el código fuente de la clase cl.getsoftware.jdirmonitor.task.NormalTaskMonitor:<br />
</span><br />
<pre class="brush: java;">/*
* JDirMonitor a listener of files
* Copyright (C) 2010 GetSoftware Group
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* This library was written by Eugenio Contreras for GetSoftware Group
* Contact email: contacto@getsoftare.cl
*/
package cl.getsoftware.jdirmonitor.task;
import java.io.File;
import cl.getsoftware.jdirmonitor.AbstractTaskMonitor;
/**
* <p>Tarea de monitoreo de directorio que analiza solamente los archivos que se
* encuentran en el primer nivel del directorio especificado.</p>
*
* @author egacl
*
*/
public class NormalTaskMonitor extends AbstractTaskMonitor {
/** (non-Javadoc)
* @see cl.getsoftware.jdirmonitor.AbstractTaskMonitor#monitorRutine(java.io.File)
*/
@Override
public void monitorRutine(File directory) {
this.normalRutine( this.getFilesOfDirectory(directory) );
}
public void normalRutine( File []files ){
for( File file : files ){
if( file.exists() ){
if( file.isFile() ){
this.fileMonitor( file );
}
}
}
}
}
</pre>
El método monitorRutine se ejecuta cada vez que el DirectoryMonitor inicia la rutina de monitoreo y le envía como parámetro el objeto java.io.File del directorio a analizar. Por lo tanto allí puedes escribir la manera en que deseas realizar el monitoreo.<br />
<br />
Puedes descargar el archivo <a href="http://www.4shared.com/rar/2OAIeqtq/JDirMonitor.html">JDirMonitor.rar</a> (proyecto Eclipse con javadoc incluida).<br />
Api JAR <a href="http://www.4shared.com/file/7CcWdUgW/JDirMonitor.html">JDirMonitor.jar</a><br />
<br />
EJEMPLO DE COMO UTILIZAR LA API <a href="http://www.4shared.com/rar/LEGLHfKN/JDirMonitorTester.html">AQUI</a>
<br />
<br />
egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com27tag:blogger.com,1999:blog-642435085995512969.post-14798847069389656552012-04-19T23:49:00.001-03:002012-04-20T16:01:40.011-03:00JPlanarity la primera versión Java de un planarity (Actualizado 19/04/2012)<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsGI2k7T4aqNa6IJwiXk3w3JlIGFrxTRNXF56mz8k3kM4pNVJ0rnG5VzuyJ7nFvVnI4NPfUtvlDqidjc8iCMW1Wm6la2niGEy_Zq687VEIMa23IvE9aexrVDo5JUOF9Rl3XGaYyNhWZRs/s1600-h/logo.png"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5366689092900985202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsGI2k7T4aqNa6IJwiXk3w3JlIGFrxTRNXF56mz8k3kM4pNVJ0rnG5VzuyJ7nFvVnI4NPfUtvlDqidjc8iCMW1Wm6la2niGEy_Zq687VEIMa23IvE9aexrVDo5JUOF9Rl3XGaYyNhWZRs/s320/logo.png" style="cursor: hand; cursor: pointer; float: left; height: 86px; margin: 0 10px 10px 0; width: 266px;" /></a><br />
Hace unos años atrás, mientras estaba estudiando, el cuarto semestre de Ingeniería... creo, me dieron una tarea que consistía en hacer un <a href="http://en.wikipedia.org/wiki/Planarity">Planarity</a>.<br />
El resultado fue el juego JPlanarity (la J es porque está desarrollado en lenguaje Java).<br />
<span id="fullpost"><br />
Posee un buen renderizado, selección múltiple (en beta) y permite guardar partidas, ya que no es muy entretenido avanzar a altos niveles y luego empezar todo de nuevo. A todo esto ... yo llegué al nivel 15, un profesor al 18<br />
con la esperanza de que fallara pero no fue así xD jejeje.<br />
<br />
Puedes descargar el juego presionando <a href="http://www.4shared.com/file/yz81UlrN/JPlanarity.html">AQUI</a>.<br />
<br />
<br />
<br />
<br />
El juego consiste en desenredar la red formada por las distintas aristas y vértices, como se puede ver en la imagen.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi89dY40uHWz-q-DjFXtLALvVm3sTik7GaieshrCGn1A6rku1z4L_aQPy0iapVn4-BFeeQWR7llukoyAH6dOstwcKAKkO0Ws7BAel13eNzZrtWpu6x52BpK_4YtQzRscYqYFy0iYe3epLc/s1600-h/jplanarity.png"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5366690591632042754" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi89dY40uHWz-q-DjFXtLALvVm3sTik7GaieshrCGn1A6rku1z4L_aQPy0iapVn4-BFeeQWR7llukoyAH6dOstwcKAKkO0Ws7BAel13eNzZrtWpu6x52BpK_4YtQzRscYqYFy0iYe3epLc/s320/jplanarity.png" style="cursor: hand; cursor: pointer; display: block; height: 279px; margin: 0px auto 10px; text-align: center; width: 320px;" /></a><br />
<br />
<br />
Cualquier sugerencia, bugs o nueva idea se acepta y comentala aquí.<br />
<br />
Saludos.-<br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com1tag:blogger.com,1999:blog-642435085995512969.post-8277803359098316142010-05-04T01:29:00.001-04:002010-05-04T01:32:57.106-04:00IDEs para programar en GroovyEn el <a href="http://getgeeks.blogspot.com/2010/04/un-primer-vistazo-groovy.html" target="_blank">post anterior de Groovy</a> se mostró una pequeña introducción sobre este moderno y poderoso lenguaje de programación. Pero ¿Qué se necesita para poder desarrollar aplicaciones en Groovy?<br />
<br />
<span id="fullpost"><br />
*Requisito obligatorio es tener instalada la <a href="http://java.sun.com/javase/downloads/index.jsp" target="_blank">JVM</a>.<br />
<br />
Lo primero que se debe hacer es descargar el <a href="http://groovy.codehaus.org/Download" target="_blank">Groovy Develpment Kit (GDK)</a>. Luego la instalación consiste simplemente en descomprimir el GDK en la ruta que desees y crear una variable de entorno GROOVY_HOME en linux o agregar la ruta al directorio /bin de groovy en la variable de entorno PATH en windows.<br />
Para información más detallada visita el <a href="http://groovy.codehaus.org/Tutorial+1+-+Getting+started" target="_blank">tutorial de groovy en su sitio oficial</a>.<br />
<br />
Una vez realizado lo anterior, está todo listo para empezar a programar en Groovy, ya que este proporciona un interprete IDE llamado GroovyConsole, en donde podrás codificar y ejecutar en un instante (para ejecutar la consola de Groovy, basta con ejecutar el comando groovyConsole o groovyConsole.bat).<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a target="_blank" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBdV3ziUqKNWgLfV1vWvIWNQgqxackjws91fbo7GmDtuEIFibiIRj5r1oZNHawGMU-tdH9_rPfVXOLWXUsiswASZagXjqcUnNugaUWS0fx6z47TBl02bTEQwt8DXXWt1JcvcRt1dMtkQM/s1600/groovyConsole.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBdV3ziUqKNWgLfV1vWvIWNQgqxackjws91fbo7GmDtuEIFibiIRj5r1oZNHawGMU-tdH9_rPfVXOLWXUsiswASZagXjqcUnNugaUWS0fx6z47TBl02bTEQwt8DXXWt1JcvcRt1dMtkQM/s320/groovyConsole.png" width="320" /></a><br />
(groovyConsole en acción)</div><br />
La comunidad de Groovy ha desarrollado también un plugin para eclipse llamado <a href="http://groovy.codehaus.org/Eclipse+Plugin" target="_blank">Groovy-Eclipse</a>, el cual permite fácilmente desarrollar y compilar proyectos en Groovy (en el link encontrarán una sección 'How to Install' con los pasos a seguir para la instalación).<br />
<br />
Y como si fuera poco, la comunidad Groovy en conjunto con Spring Source han desarrollado una completa plataforma sobre Eclipse, que permite crear fácilmente proyectos en Groovy, <a href="http://www.grails.org" target="_blank">Grails</a>, <a href="http://www.eclipse.org/aspectj" target="_blank">AspectJ</a>, etc. El proyecto se llama 'Grails - STS Integration' y lo puedes descargar desde <a href="http://www.grails.org/STS+Integration" target="_blank">AQUI</a>.<br />
<br />
En las siguientes entradas se verán códigos de ejemplo con Groovy (desde los más simple a lo complejo) hasta llegar al nivel necesario para desarrollar utilizando Grails.<br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com1tag:blogger.com,1999:blog-642435085995512969.post-70925603909466248042010-05-02T00:38:00.001-04:002010-05-02T00:47:38.594-04:00Colecciones en Python<div class="separator" style="clear: both; text-align: center;"><a href="javascript:void(0);" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT5Dxq_5Jc7LUKPnKgm3Ij1GYbe1XYTWLpOpBd8oP3vcxBtlkayx5iPZUCVM2HlQOUiQZ9j7sLP6wpRiHm3L2UGJS-89BYyQM2SPi0j81m28ebIGcRvafImOz3sNRl472EWScxWyxXM14/s200/python-logo.jpg" width="146" /></a></div><br />
Anteriormente habíamos visto <a href="http://getgeeks.blogspot.com/2009/08/tipos-de-datos-basicos-en-python.html" target="_blank">algunos tipos básicos de datos</a> como los booleanos, enteros y cadenas de texto.<br />
<br />
A continuación veremos como utilizar algunos tipos de colecciones que nos ofrece Python.<br />
<span id="fullpost"><br />
<h2>Listas</h2><br />
Las listas son colecciones de datos ordenadas y son el equivalente a los ArrayList o vectores de Java o C#.<br />
En Python las listas y las colecciones en general pueden almacenar cualquier tipo de dato, como objetos, números, colecciones, etc.<br />
<br />
Este es un ejemplo donde podremos ver cómo utilizar las listas:<br />
<br />
<pre class="brush: python;">if __name__ == '__main__': #equivale a public static void main de Java
listado = [] #inicializamos una lista
print("Todo lo que escribas sera guardado en una lista")
while True:
dato = raw_input("> ");
if( dato=="fin" ):
break
#se agrega al final de la lista un nuevo elemento
listado.append(dato)
if listado.__len__()>0:
print("Estos son los datos ingresados")
for i in listado:
#la coma permite imprimir el contenido en
# una sola fila como un System.out.print de Java
print i ,
else:
print("No se ingreso nada en la lista")
</pre><br />
Python posee una característica denominada <b>slicing</b> y que permite seleccionar u obtener una partición de la lista, por ejemplo:<br />
<pre class="brush: python;">lista = ["h","o","l","a"," ","m","u","n","d","o"]
print( lista[2:5] ) #1) imprime ['l', 'a', ' ']
print( lista[:4] ) #2) imprime ['h', 'o', 'l', 'a']
print( lista[5:] ) #3) imprime ['m', 'u', 'n', 'd', 'o']
print( lista[:] ) #4) imprime ['h', 'o', 'l', 'a', ' ', 'm', 'u', 'n', 'd', 'o']
print( lista[0:4:2] ) #5) imprime ['h', 'l']
print( lista[::2] ) #6) imprime ['h', 'l', ' ', 'u', 'd']
print( lista[::3] ) #7) imprime ['h', 'a', 'u', 'o']
</pre><br />
En el caso '1' se obtiene un fragmento del arreglo desde la posición 2 hasta la 4.<br />
En el caso '2' se imprime el arreglo desde la posición 0 hasta la 3.<br />
En el caso '3' se imprime el arreglo desde la posición 5 hasta la última (9).<br />
En el caso '4' se imprime todo el arreglo.<br />
*<b>cuando no se especifica un número a la izquierda del slicing (:) se toma por defecto la primera posición del arreglo y a la derecha se toma la última posición.</b><br />
En el caso '5' imprime desde la posición 0 hasta la 3 cada 2 caracteres.<br />
En el caso '6' imprime desde la posición 0 hasta la 9 cada 2 caracteres.<br />
En el caso '7' imprime desde la posición 0 hasta la 9 cada 3 caracteres.<br />
<br />
<br />
<h2>Tuplas</h2><br />
Las tuplas se manejan exactamente igual a las listas, y las características más relevantes que poseen son:<br />
-A diferencia de las listas ([]), las tuplas se inicializan con ().<br />
-Son inmutables, es decir, su contenido no puede ser modificado.<br />
-Tienen tamaño fijo.<br />
-Utilizan menos memoria que las listas.<br />
<br />
<pre class="brush: python;">lista = ["h","o","l","a"," ","m","u","n","d","o"]
unaTupla = tuple( lista )
print( unaTupla[2:5] ) #1) imprime ['l', 'a', ' ']
</pre><br />
<br />
<h2>Diccionarios</h2><br />
Los diccionarios son colecciones que permiten relacionar una clave con un valor y son el equivalente a los HashMap de Java.<br />
La principal diferencia entre los diccionarios con las tuplas y listas, es que sus valores no son accedidos a través de un índice, porque no poseen orden (ya que los diccionarios se implementan como <a target="_blank" href="http://es.wikipedia.org/wiki/Tabla_hash">tablas hash</a>), sino que mediante su clave utilizando el operador [clave]. Por esta misma razón es que tampoco puede aplicarse <b>slicing</b> sobre estas.<br />
<br />
Este es un ejemplo de diccionario:<br />
<pre class="brush: python;">numeros = {"uno":1, "dos":2, "tres":3, 4:"cuatro", 5:"cinco", 6:"seis"}
print( numeros["uno"] ) #1) imprime 1
print( numeros[5] ) #2) imprime cinco
print( numeros.keys() ) #3) imprime [4, 5, 6, 'dos', 'tres', 'uno']
print( numeros.values() ) #4) imprime ['cuatro', 'cinco', 'seis', 2, 3, 1]
</pre><br />
-En el caso 1 se imprime el valor obtenido de la llave 'uno'.<br />
-En el caso 2 se imprime el valor de la llave '5'.<br />
-En el caso 3 se imprimen todas las llaves del diccionario.<br />
-En el caso 4 se imprimen todos los valores del diccionario.<br />
<br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-28739123495706073932010-04-28T12:15:00.002-04:002010-04-28T12:32:15.618-04:00Un primer vistazo a Groovy<div class="separator" style="clear: both; text-align: center;"><a href="javascript:void(0);" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://media.xircles.codehaus.org/_projects/groovy/_logos/medium.png" /></a></div>Actualmente en todo el mundo los lenguajes dinámicos o ágiles han logrado alcanzar mucha popularidad tanto en las empresas como para los desarrolladores (aunque en Chile y en general en Latino América, a nivel empresarial aún no son muy valorados).<br />
<br />
<span id="fullpost"><br />
<a href="http://groovy.codehaus.org" target="_blank">Groovy</a> me ha llamado poderosamente la atención ya que es un lenguaje nacido con la misión de llevarse bien con Java, vivir en la máquina virtual y soportar los tipos de datos estándar pero añadiendo características dinámicas y sintácticas presentes en lenguajes como <a href="http://getgeeks.blogspot.com/search/label/python" target="_blank">Python</a>, <a href="http://www.smalltalk.org" target="_blank">Smalltalk</a> o <a href="http://www.ruby-lang.org/es" target="_blank">Ruby</a>.<br />
<br />
El código fuente de Groovy compila a bytecodes igual que Java (generando archivos .class que podemos ejecutar directamente desde la máquina virtual), lo que permite <b>instanciar objetos Java desde Groovy y viceversa</b>.<br />
<br />
La sintaxis de Groovy es bastante similar a la de Java, por lo que la curva de aprendizaje es muy alta para los desarrolladores que se familiarizan con él.<br />
<br />
La mayoría de las cosas que hacemos con Java puede hacerse en Groovy, por ejemplo:<br />
<ul><li>Definición de <a href="http://en.wikipedia.org/wiki/Java_package" target="_blank">packages</a></li>
<li>Definición de clases (pero no internas) y métodos</li>
<li>Estructuras de control, excepto el bucle for( ; ; )</li>
<li>Control de excepciones</li>
<li>Operadores, expresiones y asignaciones</li>
<li><a target="_blank" href="http://es.wikibooks.org/wiki/Programaci%C3%B3n_en_Java/Literales">Literales</a> con algunas variaciones</li>
<li>Instanciación, referencia y de-referencia de objetos, llamadas a métodos</li>
</ul>Y algunas mejoras sintácticas que incluye Groovy:<br />
<ul><li>En Groovy <b>todo</b> es un objeto</li>
<li>Facilidad en el manejo de objetos, a través de nuevas expresiones y sintaxis</li>
<li>Diversas formas para declarar literales</li>
<li>Control de flujo avanzado mediante nuevas estructuras</li>
<li>Nuevos tipos de datos con operaciones y expresiones específicas</li>
<li><b>Brevedad</b>, el código Groovy es mucho más breve que el de Java</li>
</ul><br />
Y como es habitual y para finalizar esta entrada, veamos como sería el código del típico "Hola Mundo" en Groovy:<br />
<br />
<pre class="brush: java;">//Hola Mundo en Groovy
def mundo = "Mundo"
println "Hola $mundo!"
//Fin
</pre><br />
A primera vista vemos que:<br />
<ul><li>Se pueden escribir script en los que no hay clases (en realidad la hay pero no necesitamos declararla)</li>
<li>No hay ';' al final de cada línea. En Groovy es opcional</li>
<li>La palabra reservada <b>def</b> permite declarar variables de tipo dinámico. También se pueden crear variables de tipo estático (ejemplo: Integer)</li>
<li>Los comentarios son igual que en Java (// o /**/)</li>
<li><b>print</b> y <b>println</b> son equivalentes a System.out.print y System.out.println</li>
<li>El parámetro de la función <b>println</b> no va entre paréntesis, es opcional</li>
</ul></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-9742756143242562602010-04-03T01:42:00.004-03:002012-11-14T10:19:10.379-03:00JavaMail, envío de mail con archivos adjuntos y formato HTML a través de Google Apps o noHola a todos, a muchos desarrolladores se nos hace indispensable poder implementar un módulo de envío de mail en los sistemas que desarrollamos. Dependiendo del lenguaje está la complejidad o simplicidad de la codificación de éste y como muchos sabemos, Java no siempre es un precursor de lo simple.<br />
<span id="fullpost"><br />
Es por esto que quiero publicar y facilitarles a todos una clase Mail.java que permite realizar envío de correos a través de <a href="http://www.google.com/apps/intl/es/business/gmail.html">Google Apps</a> y mediante un servidor de correos común y corriente.<br />
<br />
El código funciona implementando la API de SUN <a href="http://www.blogger.com/Este%20es%20el%20link%20de%20la%20API%20JavaMail%20-%3E%20http://www.oracle.com/technetwork/java/javamail/index.html">JavaMail</a> (así que descarguen el JAR con la API sino nunca podrán enviar correos) y proporciona 2 métodos. Uno llamado 'enviaGoogleApp' que permite enviar el correo a través de una cuenta de Google Apps y otro llamado 'envia' que envía correos a través de un servidor de correo definido.<br />
<br />
El código de ambos métodos es idéntico, sólo cambia la forma de autenticarse en el servidor.<br />
<br />
Los métodos de la clase Mail sólo requieren los siguientes datos:<br />
1) Emisor del mensaje.<br />
2) Asunto del correo.<br />
3) Receptor(es) del correo.<br />
4) mensaje del correo (en formato HTML o ASCII)<br />
5) Archivos adjuntos.<br />
<br />
Con una leve modificación y añadiendo 2 parámetros más se pueden añadir:<br />
1) Receptores a quienes se copia el correo.<br />
2) Receptores a quienes se les envía copia oculta.<br />
<br />
El código es el siguiente:<br />
<br />
</span><br />
<pre class="brush: java;"><span id="fullpost">package util.mail;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
public class Mail {
private class SMTPAuthenticator extends Authenticator {
private String dEmail;
private String dPassword;
public SMTPAuthenticator(String email, String password){
dEmail = email;
dPassword = password;
}
public PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication(dEmail, dPassword);
}
}
/**
* Funci&oacute;n que permite enviar un correo electr&oacute;nico con archivos adjunto.
* &lt;br&gt;El contenido del correo puede estar en formato HTML.
* @param emisor Correo de qui&eacute;n emite el correo
* @param asunto Asunto del e-mail
* @param receptores Correos de los receptores del e-mail
* @param mensaje Mensaje del e-mail
* @param adjuntos Ruta de archivos adjuntos en el e-mail
* @return TRUE si el mail fue enviado con &eacute;xito, FALSE en caso contrario
*/
public boolean enviaGoogleApp(String emisor, String asunto, List&lt;String&gt; receptores, String mensaje, List&lt;String&gt; adjuntos){
boolean envioExitoso = true;
String emailGetCursos = "cuenta.googleapps@algo.cl";
String password = "password.de.cuenta.googleapps";
Properties props = new Properties();
props.put("mail.smtp.user", emisor);
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.socketFactory.port", "465");
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");
try{
Authenticator auth = new SMTPAuthenticator(emailGetCursos, password);
Session session = Session.getInstance(props, auth);
MimeMessage message = new MimeMessage(session);
InternetAddress[] dest = new InternetAddress[receptores.size()];
for (int i=0;i&lt;dest.length;i++){
dest[i] = new InternetAddress( receptores.get(i) );
}
//Se define qui&eacute;n es el emisor del e-mail
message.setFrom(new InternetAddress(emisor));
InternetAddress[] replyTo = new InternetAddress[1];
replyTo[0] = new InternetAddress( emisor );
message.setReplyTo( replyTo );
//Se definen el o los destinatarios
message.addRecipients(Message.RecipientType.TO, dest);
//message.addRecipients(Message.RecipientType.CC, dest);
//message.addRecipients(Message.RecipientType.BCC, dest);
//Se defina el asunto del e-mail
message.setSubject(asunto);
//Se seteo el mensaje del e-mail
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(message,"text/html");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
//Se adjuntan los archivos al correo
if( adjuntos!=null && adjuntos.size()>0 ){
for( String rutaAdjunto : adjuntos ){
messageBodyPart = new MimeBodyPart();
File f = new File(rutaAdjunto);
if( f.exists() ){
DataSource source = new FileDataSource( rutaAdjunto );
messageBodyPart.setDataHandler( new DataHandler(source) );
messageBodyPart.setFileName( f.getName() );
multipart.addBodyPart(messageBodyPart);
}
}
}
//Se junta el mensaje y los archivos adjuntos
message.setContent(multipart);
//Se env&iacute;a el e-mail
Transport.send( message );
}
catch (Exception e) {
envioExitoso = false;
}
finally{
//Se eliminan del servidor los archivos adjuntos
if( adjuntos!=null && adjuntos.size()&gt;0 ){
for( String rutaAdjunto : adjuntos ){
try{
File arch = new File(rutaAdjunto);
arch.delete();
}
catch (Exception e) {}
}
}
}
return envioExitoso;
}
/**
* Funci&oacute;n que permite enviar un correo electr&oacute;nico con archivos adjunto.
* &lt;br&gt;El contenido del correo puede estar en formato HTML.
* @param emisor Correo de qui&eacute;n emite el correo
* @param asunto Asunto del e-mail
* @param receptores Correos de los receptores del e-mail
* @param mensaje Mensaje del e-mail
* @param adjuntos Ruta de archivos adjuntos en el e-mail
* @return TRUE si el mail fue enviado con &eacute;xito, FALSE en caso contrario
*/
public boolean envia(String emisor, String asunto, List&lt;String&gt; receptores, String mensaje, List&lt;String&gt; adjuntos){
boolean envioExitoso = true;
try{
Properties props = System.getProperties();
//Se define el servidor de correos
props.put("mail.smtp.host", "ip.servidor.de.correos");
props.put("mail.smtp.port", "puerto.servidor.de.correo (por defecto 25)");
//Se obtiene sesi&oacute;n desde el servidor de correos
Session session = Session.getInstance(props, null);
session.setDebug(true);
MimeMessage message = new MimeMessage(session);
InternetAddress[] dest = new InternetAddress[receptores.size()];
for (int i=0;i&lt;dest.length;i++){
dest[i] = new InternetAddress( receptores.get(i) );
}
//Se define qui&eacute;n es el emisor del e-mail
message.setFrom(new InternetAddress(emisor));
InternetAddress[] replyTo = new InternetAddress[1];
replyTo[0] = new InternetAddress( emisor );
message.setReplyTo( replyTo );
//Se definen el o los destinatarios
message.addRecipients(Message.RecipientType.TO, dest);
//message.addRecipients(Message.RecipientType.CC, dest);
//message.addRecipients(Message.RecipientType.BCC, dest);
//Se defina el asunto del e-mail
message.setSubject(asunto);
//Se seteo el mensaje del e-mail
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(message,"text/html");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
//Se adjuntan los archivos al correo
if( adjuntos!=null && adjuntos.size()>0 ){
for( String rutaAdjunto : adjuntos ){
messageBodyPart = new MimeBodyPart();
File f = new File(rutaAdjunto);
if( f.exists() ){
DataSource source = new FileDataSource( rutaAdjunto );
messageBodyPart.setDataHandler( new DataHandler(source) );
messageBodyPart.setFileName( f.getName() );
multipart.addBodyPart(messageBodyPart);
}
}
}
//Se junta el mensaje y los archivos adjuntos
message.setContent(multipart);
//Se env&iacute;a el e-mail
Transport.send( message );
}
catch (Exception e) {
envioExitoso = false;
}
finally{
//Se eliminan del servidor los archivos adjuntos
if( adjuntos!=null && adjuntos.size()&gt;0 ){
for( String rutaAdjunto : adjuntos ){
try{
File arch = new File(rutaAdjunto);
arch.delete();
}
catch (Exception e) {}
}
}
}
return envioExitoso;
}
public static void main(String[] args) {
List&lt;String&gt; receptores = new ArrayList&lt;String&gt;();
receptores.add("mail.de.alguien@gmail.com");
String emisor = "test@test.cl";
String asunto = "Correo de prueba";
String mensaje = "Este es un correo de &lt;font color='red'&gt;&lt;b&gt;PRUEBA&lt;/b&gt;&lt;/font&gt;";
List&lt;String&gt; archivos = new ArrayList&lt;String&gt;();
Mail m = new Mail();
//m.envia(emisor, asunto, receptor, mensaje, null);
m.enviaGoogleApp( emisor, asunto, receptores, mensaje, archivos);
}
}
</span></pre>
egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com14tag:blogger.com,1999:blog-642435085995512969.post-51831124707397406322010-01-20T11:34:00.029-03:002010-04-02T21:50:34.369-03:00Métodos Javascript que te pueden ser útilesHola a todos, Ufff hace mucho que no publico una entrada contundente. La verdad he estado demasiado ocupado realizando mi tesis de la cual les hablaré en un tiempo más... cuando la termine.<br />
<br />
Este post algo tiene que ver con mi tesis y son algunos de los métodos javascript que he tenido que construir para facilitar la obtención de datos y validaciones (a pesar de que ya existen frameworks como JQuery que ya lo hacen, siempre es mejor saber como se hacen las cosas antes que la total abstracción).<br />
<br />
<span id="fullpost"><br />
<br />
El siguiente método obtiene todos los elementos HTML de un tipo específico y cuyo ID cumpla con patrón recibido como parámetro.<br />
<br />
<pre class="brush: java;">function getElementsLikeID( tagName, likeID ){
var elementsLike = [];
var elementos = document.getElementsByTagName( tagName );
if( elementos!=null ){
var j=0;
for( i=0 ; i<elementos.length ; i++ ){
if( elementos[i].id!=null && elementos[i].id.indexOf(likeID)>-1 ){
elementsLike[j++] = elementos[i];
}
}
}
return elementsLike;
}
</pre><br />
<br />
Si ejecutas getElementsLikeID('INPUT','porcentajes_'); devolverá un arreglo con todos los elementos HTML input cuyo ID contenga la palabra 'porcentajes_'.<br />
<br />
<br />
Utilizando el método "getElementsLikeID" se pueden hacer una infinidad de funciones, por ejemplo una que permita cambiar la clase de diversos elementos de la página.<br />
<br />
<pre class="brush: java;">function cambiaClassPorTag( tagName, likeID, nombreClase ){
var elementos = getElementsLikeID( tagName, likeID );
if( elementos!=null ){
for( i=0 ; i<elementos.length ; i++ ){
elementos[i].className = nombreClase;
}
}
</pre><br />
<br />
Por ultimo les dejo unos métodos que sirven para marcar varios checkbox que posean un nombre en común y otro para marcar todos los checkbox que estén dentro de una columna de una tabla (al hacer click en la columna se marcan todos los checkbox).<br />
<br />
1) Marcar o descmarcar todos los checkbox con nombre en común.<br />
<br />
<pre class="brush: java;">function checkBoxLikeNameMarcar( name ){
checkBoxLikeName( name, true );
}
function checkBoxLikeNameDesmarcar( name, marcar ){
checkBoxLikeName( name, false );
}
function checkBoxLikeName( name, marcar ){
var checkBoxes = document.getElementsByTagName('INPUT');
for ( i=0 ; i<checkBoxes.length ; i++){
if(checkBoxes.type='CHECKBOX' && checkBoxes[i].name.indexOf(name)>-1){
if( marcar && !checkBox[i].checked )
checkBoxes[i].click();
else if ( !marcar && checkBoxes[i].checked )
checkBoxes[i].click();
}
}
}
</pre><br />
<br />
2)Marcar todos los checkbox de una columna de una tabla.<br />
*El parámetro "aLink" es un link que va en un o al principio de la columna.<br />
<br />
<pre class="brush: java;">function checkColumna( aLink ){
var tdPresionado = aLink .parentNode;
var trTabla = td.parentNode;
var pos = 0;
for( var i=0 ; i<trTabla.cells.length ; i++ )
if( tr.cells[i]==tdPresionado )
pos = i+1;
for( var i=2 ; i<trTabla.parentNode.rows.length ; i++ ){
trTabla.parentNode.rows[i].cells[pos].getElementsByTagName('INPUT')[0].click();
}
</pre><br />
<br />
Bueno eso es todo por ahora, espero les sirva ;)<br />
Saludos<br />
<br />
PD: Feliz navidad y año nuevo ultra atrasado xD.<br />
<br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-15108784654352730222009-12-14T10:22:00.002-03:002009-12-14T10:27:39.939-03:00Frases: Software y catedralesEl software y las catedrales se parecen mucho. Primero lo construimos, después rezamos.<br /><br />–-Anónimoegaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-12149526048949975262009-11-05T12:35:00.003-03:002009-11-05T12:40:14.614-03:00Frases: Programación"Los programas deben ser escritos para que la gente los lea y sólo incidentalmente, para que las máquinas los ejecuten."<br /><br />---<a href="http://en.wikipedia.org/wiki/Hal_Abelson">Abelson</a> / <a href="http://en.wikipedia.org/wiki/Gerald_Jay_Sussman">Sussman</a><br /><br /><br />visto en: <a href="http://www.hackification.com/2008/12/23/a-double-handful-of-programming-quotes/">hackification</a>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-61133061925043846162009-10-20T12:16:00.007-03:002009-11-10T10:45:03.285-03:00Gestiona tu proyecto facilemente con ScrumyNavegando por ahí me encontré con <a href="http://scrumy.com/about">Scrumy</a> una herramienta que permite organizar y gestionar las tareas que se deben realizar en un proyecto con todo el estilo de Scrum.<br /><br />No hay mucho más que decir les dejo el link del sitio, el cual permite crear proyectos de manera gratuita en su modo FREE o puedes pagar un poco para acceder a todas las funcionalidades en su modo PRO: <a href="http://scrumy.com">SCRUMY!!</a><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2CQvPFinCOQE7C7H6ygeH3qzoebtTxb9C0VDLfmFtE023uEQZtwMHU-1b3rZCNdwKEkE6xk_BXXktB_ENuXwTyIliIxfV_LZ3EjhhLBfGzJbymDVvzH0Sf6vhnrxCcqrDR1QUXHvEomA/s1600-h/main-logo.png"><img style="float:center; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 354px; height: 112px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2CQvPFinCOQE7C7H6ygeH3qzoebtTxb9C0VDLfmFtE023uEQZtwMHU-1b3rZCNdwKEkE6xk_BXXktB_ENuXwTyIliIxfV_LZ3EjhhLBfGzJbymDVvzH0Sf6vhnrxCcqrDR1QUXHvEomA/s400/main-logo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5394703806582247202" /></a><br /><br />Aquí les dejo un video que explica de qué trata SCRUMY:<br /><span id="fullpost"><br /><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/DmZ5O5AJ2F4&hl=es&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/DmZ5O5AJ2F4&hl=es&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-90304049372934256632009-10-19T12:12:00.010-03:002009-10-19T12:53:48.505-03:00¿Necesitas iconos para tu web?Hola a todos.<br /><br />Siempre cuando desarrollamos un sistema llega el momento de escoger qué <br />iconos utilizarás. Si eres nuevo y no tienes ideas de las licencias <br />que pueden tener las imágenes que circulan en la web, pues debo decirte<br />que no puedes llegar y tomar los iconos que quieras...<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://commons.wikimedia.org/wiki/Main_Page" target="_blank"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 135px; height: 155px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX68adE84-bwt1YxOEJxIiTRnfehRbTiigGo4XT_65GhGcCRgqTB8b0y0WGjxv3tOO6JeqGwZvGuyxkaqy1bAKrna59rissbPGBmzhFgKkvSDN-Ra1IbzMprNTdBTa9wTki-unkR2XBmY/s400/Wiki-commons.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5394333274085815554" /></a><br />Excepto en <a href="http://commons.wikimedia.org/wiki/Category:Icons_themes" target="_blank">Wikimedia Commons</a> donde encontrarás una cantidad impresionante de imágenes (en formato PNG y SVG) e iconos bajo licencia "GNU General Public License" más conocida como "GNU GPL" o "GPL".<br /><br />Para más información visita los siguientes enlaces:<br /><a href="http://en.wikipedia.org/wiki/GNU_General_Public_License">GNU GPL (Wiki)</a><br /><a href="http://www.gnu.org/copyleft/gpl.html">GNU GPL (Sitio oficial)</a><br /><br />Saludos.-egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-59249731437826412412009-09-14T17:19:00.005-04:002009-09-14T17:26:04.105-04:00Frases: Proyectos"Si deseas empezar y desarrollar algo grandioso, no necesitas millones de dólares de capitalización. Necesitas suficiente pizza y Diet Coke en la nevera, una PC barata y trabajo y dedicación para realizar tu idea."<br /><br />---<a href="http://en.wikipedia.org/wiki/John_D._Carmack">John Carmack</a><br /><br /><br />visto en: <a href="http://www.hackification.com/2008/12/23/a-double-handful-of-programming-quotes/">hackification</a>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com2tag:blogger.com,1999:blog-642435085995512969.post-4714166251403676732009-08-26T00:12:00.006-04:002009-09-03T12:31:46.604-04:00¿Cómo aplicarías SCRUM?Mencionábamos sobre la <a href="http://getgeeks.blogspot.com/2009/08/scrum-metodologia-de-desarrollo-de.html">metodología ágil de desarrollo SCRUM</a> permite, entre otras cosas, involucrar al cliente durante todo el proceso de desarrollo, además de motivar constantemente al equipo de trabajo a través de breves reuniones diarias. Todo el equipo conoce perfectamente en qué punto del desarrollo se encuentra el proyecto y qué falta por hacer.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPEnomXi12eZGbZQwG4YoGkB1MNPgPu0Qrr1PZaFh2IEUJLGtydOg4rjYQtTkKBwgQf9xXA8qR9BSxV_PV7pWDiqC6kpr1PeO-U4QbbQxRXG6_uHDhYADgR1mCOxQVp-Ik9TDoz6Ffkqw/s1600-h/scrum-overview.gif"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPEnomXi12eZGbZQwG4YoGkB1MNPgPu0Qrr1PZaFh2IEUJLGtydOg4rjYQtTkKBwgQf9xXA8qR9BSxV_PV7pWDiqC6kpr1PeO-U4QbbQxRXG6_uHDhYADgR1mCOxQVp-Ik9TDoz6Ffkqw/s320/scrum-overview.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5374311194546468850" /></a><br /><br />¿Cómo aplicarías SCRUM? Aquí les dejo un ejemplo o plantilla de cómo se podría llevar aplicar:<br /><span id="fullpost"><br /><span style="font-weight:bold;">Etapa 1: Toma de requerimientos. </span><br />Definición del "Product Backlog", el cual corresponde a todas las tareas, requerimientos o funcionalidades a realizar. Esta información será recopilada a través de reuniones entre el "Scrum Team" y el "Product Owner".<br /><br /><span style="font-weight:bold;">Etapa 2: Análisis de requerimientos y Diseño Arquitectónico.</span><br />Se analizará el "Product Backlog" y a través de éste se generará el diseño base del sistema, el cual involucra por ejemplo: modelo de base de datos, principales módulos del sistema.<br /><br /><span style="font-weight:bold;">Etapa 3: Desarrollo del Sistema.</span><br />Durante todo el proceso de desarrollo, el equipo de trabajo realizará reuniones diarias de 15 a 30 minutos, denominadas "Daily Scrum Meeting". El objetivo de éstas es que todo el equipo de trabajo se entere del estado de las diversas tareas y se resuelvan dudas que puedan surgir en éste proceso.<br /><br />Mediante las "Sprint Planning Meeting" se definirán los diversos "Sprint Backlog" (conjunto de requerimientos que equivalen a un incremento del sistema), los cuales contemplarán parte de las funcionalidades descritas en el "Product Backlog". Los "Sprint Backlogs" tendrán una duración ideal de 2 semanas.<br /><br />En esta fase se genera un documento que indica los objetivos del "Sprint" denominado "Sprint Goal".<br /><br />Una vez finalizado un "Sprint Backlog", se realizará una reunión denominada "Sprint Review" donde se mostrará al "Product Owner" los avances realizados. Éste podrá revisar la entrega y hará las observaciones correspondientes.<br /><br />Por último, se inicia el "Sprint Retrospective". Donde se marcan los aspectos positivos (para repetirlos) y los aspectos negativos (para no repetirlos) experimentados en el "Spring Backlog".<br /><br />El ciclo se repite hasta abarcar todas las funcionalidades descritas en el "Product Backlog".<br /><br /><span style="font-weight:bold;">Etapa 4: Aceptación y entrega del Producto.</span><br />Contempla las siguientes tareas:<br /><ul><br /> <li>Revisión final del producto.</li><br /> <li><br /> Entrega del Sistema.<br /> <ul><br /> <li>Código Fuente</li><br /> <li>Documento de diseño arquitectónico del Sistema</li><br /> <li>Manuales de administración y uso del Sistema</li><br /> </ul><br /> </li><br /> <li>Instalación del Sistema en ambiente de producción</li><br /></ul><br /><br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com2tag:blogger.com,1999:blog-642435085995512969.post-51813545867572745882009-08-20T15:48:00.010-04:002009-08-27T09:44:58.924-04:00SCRUM: Metodología de Desarrollo de SoftwareA grandes rasgos se puede decir que SCRUM es una Metodología Ágil de desarrollo de software que se concentra en cómo los miembros del equipo deberían funcionar (comunicarse, trabajar, etc.), a fin de producir un sistema flexible en un entorno que cambia constantemente. <br /><br />La filosofía de SCRUM está en involucrar, motivar y mantener constantemente informado sobre el estado del proyecto a el equipo de trabajo y el cliente.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO8G0jpW5-pJib_rX6hQ1vg1x0S9ekINg64P6_C4T-GazJChyphenhyphennwyDKZLMzVPg1u3FDkDZD_FzW-Ult2VdIZIP4gWgAq08q9JG6gmvK0tILQJT5GPU9VJU_60uzpjFYgzgxqBd8zj8FgDo/s1600-h/scrum_logo.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 290px; height: 137px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO8G0jpW5-pJib_rX6hQ1vg1x0S9ekINg64P6_C4T-GazJChyphenhyphennwyDKZLMzVPg1u3FDkDZD_FzW-Ult2VdIZIP4gWgAq08q9JG6gmvK0tILQJT5GPU9VJU_60uzpjFYgzgxqBd8zj8FgDo/s320/scrum_logo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5372136446179293538" /></a><br /><br /><span id="fullpost"><br />Es una metodología que, para cumplirla, requiere de mucha responsabilidad por parte del equipo de trabajo. El cual consta de un jefe de proyecto, un equipo de desarrollo y el cliente.<br /><br />Hoy en día muchas empresas están adoptando ésta metodología debido a su fácil implantación y adaptabilidad a cambios.<br />Es tan simple que lo más probable (si es que has participado en proyectos en tu trabajo, universidad o instituto) hayas afrontado un proyecto de una manera muy similar (más adelante publicaré un "ejemplo de cómo se podría ejecutar SCRUM").<br /><br />A continuación definiremos los roles y conceptos de SCRUM.<br /><br />Roles:<br /><ul><br /><li>Product Owner: Conoce y marca las prioridades del proyecto o producto (cliente).</li><br /><li>Scrum Master: Guía las reuniones y ayuda al equipo ante cualquier problema que pueda aparecer (Jefe de proyecto).</li><br /><li>Scrum Team: Son los responsables de implementar las funcionalidades o requerimientos elegidos por el Product Owner. Desarrollan el producto.</li><br /><li>Stackeholders: Personas relacionadas con el producto o su financiamiento. Participan durante los Sprint Review y pueden aportar ideas, sugerencias o necesidades.</li><br /><li>Usuarios: Son los beneficiarios finales del producto.</li><br /></ul><br /><br />Actividades principales:<br /><ul><br /><li>Product Backlog: Pila de requerimientos o funciones del sistema, definida y priorizada por el Product Owner.</li><br /><li>Sprint Backlog: Pila de funcionalidades a desarrollar durante una iteración o sprint extraídas del Product Backlog. Estos desarrollos se aconseja no superen cuatro semanas, de esta manera se mantiene un control del proyecto.</li><br /><li>Spring Planning Meeting: Reuniones entre el Scrum Master, Scrum Team y Product Owner y consiste en planificar las tareas a desarrollar en un número determinado de Sprint Backlogs. Se genera un documento que indica los objetivos del Sprint denominado Sprint Goal.</li><br /><li>Daily Scrum Meeting: Pequeñas reuniones entre el Scrum Master y el Scrum Team, cuya duración no supera los 30 minutos. Se realizan durante el desarrollo del Spring Backlog y consiste en informar el estado de éste, respondiendo a las siguientes preguntas:<br /> <ul><br /> <li>¿Qué tareas has realizado desde la última reunión? (qué he hecho).</li><br /> <li>¿Sobre qué tareas trabajarás en el día actual? (que voy a hacer hoy).</li><br /> <li>¿Qué obstáculos o riesgos impiden o pueden impedir el normal avance? (qué ayuda necesito).</li><br /> </ul><br /></li><br /><li>Sprint Review: Reunión de no más de dos horas de duración, que informa los avances realizados en el Sprint al Product Owner y Stackeholders.</li><br /><li>Sprint Retrospective: Actividad para reorganizar las tareas del Product Backlog. Se analizan los aspectos positivos y negativos del Sprint Backlog.</li><br /></ul><br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-67161874433711451992009-08-18T12:53:00.004-04:002009-09-14T17:24:15.522-04:00Frases: Diseño de Software"Mucho del software hoy en día se parece a una pirámide egipcia: con millones de ladrillos apilados uno encima del otro, sin integridad estructural y hecho por pura fuerza bruta y miles de esclavos."<br /><br />--<a href="http://es.wikipedia.org/wiki/Alan_Kay">Alan Kay</a><br /><br /><br />visto en: <a href="http://www.hackification.com/2008/12/23/a-double-handful-of-programming-quotes/">hackification</a>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com2tag:blogger.com,1999:blog-642435085995512969.post-67789567712947943562009-08-14T18:14:00.016-04:002010-04-28T15:36:01.273-04:00Tipos de datos básicos en PythonComo habíamos mencionado en el <a href="http://getgeeks.blogspot.com/2009/08/un-primer-vistazo-python.html">primer post de python</a>, éste es un lenguaje de tipado dinámico pero al mismo tiempo fuertemente tipado. <br />
<br />
En python tenemos los siguientes tipos básicos:<br />
<ul><li>Boleanos</li>
<li>Números (Enteros, decimales y complejos)</li>
<li>Cadenas de Texto</li>
</ul><br />
<br />
<span id="fullpost"><br />
Sintaxis para declarar boleanos:<br />
<pre class="brush: python;">algoVerdadero = True
algoFalso = False
</pre><br />
<br />
Sintaxis para declarar números:<br />
<pre class="brush: python;">#Asi de declaran variables de tipo entero
numeroPositivo = 10
numeroNegativo = -15
#Una variable float
numeroFloat = 2.0254
</pre><br />
<br />
Operadores numéricos:<br />
<pre class="brush: python;">a = 5.0
b = 3.0
print( a+b ) #imprime -> 8.0
print( a-b ) #imprime -> 2.0
print( a*b ) #imprime -> 15.0
print( b**b ) #imprime -> 9.0, representa 3.0^3.0 (potencia)
print( a/5 ) #imprime -> 1.6666
print( a//5 ) #imprime -> 1, es el resultado entero de la división
print( a%5 ) #imprime -> 2, es el resto de la división
</pre><br />
<br />
Sintaxis para declarar cadenas de texto<br />
<pre class="brush: python;">a = "Hola"
b = " Mundo"
print( a+b ) #imprime "Hola Mundo"
print( a+(b*2) ) #imprime "Hola Mundo Mundo"
</pre><br />
Si quieres comenzar a desarrollar en Python en <a href="http://getgeeks.blogspot.com/2009/08/ides-para-programar-en-python.html">ESTE LINK</a> encontrarás información sobre el interprete e IDEs.<br />
<br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-52865793873747099972009-08-13T18:00:00.000-04:002009-08-14T12:33:38.790-04:00IDEs para programar en Python<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy1F6ER6yvIYVjtpkXHf9hj8Fzt8msH97V5C9qVye7ICzMlXXPkBUlL0gUQxMnWk3kcZcRh3eJKHrwYkd_Nt5IS9kvtd8OM5wj-RX53pjk-Ov6UcC0XtGzsRzk4Tq9t1_d7kouIFACcEI/s1600-h/pydev_logo6.gif"><img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 307px; height: 120px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy1F6ER6yvIYVjtpkXHf9hj8Fzt8msH97V5C9qVye7ICzMlXXPkBUlL0gUQxMnWk3kcZcRh3eJKHrwYkd_Nt5IS9kvtd8OM5wj-RX53pjk-Ov6UcC0XtGzsRzk4Tq9t1_d7kouIFACcEI/s320/pydev_logo6.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5369581864487979442" /></a><br />En el post anterior (<a href="http://getgeeks.blogspot.com/2009/08/un-primer-vistazo-python.html">Click Aquí</a>) vimos una pequeña pincelada sobre Python y algunos de sus conceptos.<br /><br />Ahora bien ¿Qué herramientas de desarrollo podemos ocupar para programar en Python?<br /><br /><span id="fullpost"><br />Partiendo por lo más básico cuándo instalamos el <a href="http://www.python.org/download/">intérprete de python</a>, éste viene con un IDE gráfico integrado llamado <a href="http://docs.python.org/library/idle.html">IDLE</a>.<br /><br />Ahora bien, si queremos algo más sofisticado y gratis, tenemos a nuestro querido amigo <a href="http://www.eclipse.org">Eclipse IDE</a> el cual debemos complementar instalando el plugin <a href="http://pydev.sourceforge.net/">PyDev</a>. Con esto tendremos resaltado de sintaxis, autocompletado de código, refactorización, resalte de errores, etc.<br />Otros IDE gratis son: <a href="http://boa-constructor.sourceforge.net">BOA Constructor</a> y <a href="http://eric-ide.python-projects.org/">Eric</a>.<br /><br />En lo personal utilizo Eclipse+PyDev y funciona muy bien.<br /><br />Si tienes alguna duda sobre cómo configurar Eclipse para programar en Python, comentala y te ayudaré.<br /><br />Saludos.-<br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-21309388334173890162009-08-12T13:16:00.001-04:002009-08-12T13:18:35.874-04:00Frases: Programación"Cualquier tonto puede escribir código que un ordenador entiende. Los buenos programadores escriben código que los humanos pueden entender."<br /><br />--<a href="http://en.wikipedia.org/wiki/Martin_Fowler">Martin Fowler</a><br /><br /><br />visto en: <a href="http://www.hackification.com/2008/12/23/a-double-handful-of-programming-quotes/">hackification</a>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com1tag:blogger.com,1999:blog-642435085995512969.post-77384174298941291192009-08-11T14:42:00.000-04:002009-08-11T14:46:06.508-04:00Cosas que pasanPara los que trabajamos a más de alguno le parecerá familiar ésta historia.<br /><span id="fullpost"><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm3.static.flickr.com/2537/3812415648_ec726bd917_o.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 550px; height: 460px;" src="http://farm3.static.flickr.com/2537/3812415648_ec726bd917_o.jpg" border="0" alt="" /></a><br /><br />¿Y a tí en tu lugar de trabajo te ha sucedido algo parecido?<br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com2tag:blogger.com,1999:blog-642435085995512969.post-51784081170874228812009-08-07T18:17:00.001-04:002010-04-28T09:43:45.503-04:00Un primer vistazo a Python<p><br />
Hola a todos,<br />
<br />
Hace algún tiempo que tengo ganas de aprender a utilizar el lenguaje de programación Python (más detalles sobre Python <a href="http://es.wikipedia.org/wiki/Python">AQUÍ</a>)...<br />
<br />
¿Qué es Python?<br />
</p><br />
<br />
<span id="fullpost"><br />
<p><br />
Es un lenguaje interpretado o de script (a diferencia de Java que es compilado), es decir un programa intermedio (llamado "intérprete") es encargado de leer y ejecutar el código en la máquina.<br />
<br />
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEim23Mg4Wvn-CpT0hLpy4Qo8nQuqLyz-1aFHymfk9Ke8wkveFEjcqr2-ji2oEQhk1XtEUofS-5ImjjEZlmGm3JcH-2ZLpUPJYGaIx9DQeZwZnofc2H89Sc5gGaAPQr_-senmvn3xq0tfC0/s1600-h/images.jpg"><img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 150px; height: 65px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEim23Mg4Wvn-CpT0hLpy4Qo8nQuqLyz-1aFHymfk9Ke8wkveFEjcqr2-ji2oEQhk1XtEUofS-5ImjjEZlmGm3JcH-2ZLpUPJYGaIx9DQeZwZnofc2H89Sc5gGaAPQr_-senmvn3xq0tfC0/s400/images.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5368328876073104866" /></a><br />
<br />
Posee tipado dinámico, es decir, que el tipo de las variables se determinará en tiempo de ejecución. <br />
<br />
A pesar de ésto, es fuertemente tipado, esto quiere decir que no se puede tratar a una variable como si fuera de un tipo distinto al que es.<br />
<br />
Además es <a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos">Orientado a Objetos</a> (también soporta <a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_imperativa">Programación Imperativa</a>, <a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_funcional">Funcional</a> y <a href="http://es.wikipedia.org/wiki/Programaci%C3%B3n_Orientada_a_Aspectos">Orientada a Aspectos</a>) y por si fuera poco Multiplataforma. El interprete de Python está disponible para: Linux, Windows, Mac OS, etc. Por lo tanto si no se utilizan librerías o APIs que utilicen rutinas especificas de la plataforma (S.O), el código escrito en Python debiese correr en todos estos sistemas sin realizar prácticamente ningún cambio.<br />
<br />
Más adelante comenzaré a subir ejercicios básicos para que juntos aprendamos a utilizar este <b>simple</b> y poderoso lenguaje de programación.<br />
<br />
Como pequeño adelanto les dejo el código completo necesario para escribir el típico Hola Mundo:<br />
<pre class="brush: python;">print("Hola Mundo")
</pre><br />
<br />
Si quieres instalar el interprete de python para comenzar a programar, descarga el que corresponda a la plataforma que utilizas en éste enlace: <a href="http://www.python.org/download/">DESCARGA PYTHON</a><br />
<br />
Saludos.-<br />
</p><br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-26365769110656708042009-08-07T10:50:00.000-04:002009-08-07T10:53:22.180-04:00Fotos de los creadores de lenguajes de programaciónAcá les dejo el link donde encontrarás las fotos de los creadores de algunos lenguajes de programación como java, python, c#, php y más...<br /><br /><a href="http://www.programmerfish.com/popular-programming-languages/" target="_blank">Presiona AQUí</a><br /><br />¿Qué te pareció ver a los creadores de tus lenguajes de programación preferidos?<br /><br />Saludos.-egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-15841269172828019502009-08-07T10:42:00.000-04:002009-08-07T16:51:14.365-04:00Java varargs y bucles for-each<p><br />Desde Java 5 se incorporaron los conceptos de <i><b>varargs</b></i> (argumentos variables) y bucles <b><i>for-each</i></b>.<br /></p><br /><br /><span id="fullpost"><br /><p><br />El primero nos permite pasar un número variable de argumentos a un método de manera transparente. El segundo nos facilita sobre manera la manera en que se realizan los bucles for.<br /><br />Ambas funcionalidades nos entregan el mismo dinamismo proporcionado por otros lenguajes como <a href="http://es.wikipedia.org/wiki/Python" target="_blank">Python</a> o <a href="http://es.wikipedia.org/wiki/PHP" target="_blank">PHP</a>.<br /><br />Veamos un ejemplo que mezcle éstas funcionalidades<br />-La mayoría de los programadores Java escribiría código como éste:<br /><pre class="brush: java;"><br />public class VarargsForEach{<br /> public static void main(String[] args){<br /> for( int i=0 ; i<args.lengt ; i++){<br /> String argumento = args[i];<br /> System.out.println( argumento );<br /> }<br /> }<br />}<br /></pre><br /><br />-Ahora utilizando varargs y bucles for-each, nuestro código quedaría de la siguiente manera:<br /><pre class="brush: java;"><br />public class VarargsForEach{<br /> public static void main(String... args){<br /> foreach( String argumento : args ){<br /> System.out.println( argumento );<br /> }<br /> <br /> imprimir("Hola", " como", " estas ", "...", 1,2,3, " chao");<br /> }<br /> <br /> public static void imprimir( Object... parametros ){<br /> foreach( Object parametro : parametros ){<br /> System.out.println( parametro );<br /> }<br /> }<br />}<br /></pre><br /><br />Los varargs nos proporcionan mayor abstracción y flexibilidad en los métodos. Por otro lado los bucles for-each nos entregan simplicidad y elegancia en el código.<br /></p><br /><br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com0tag:blogger.com,1999:blog-642435085995512969.post-84703773430357540672009-08-07T10:06:00.004-04:002010-02-19T10:36:19.010-03:00J2EE: Struts2 + log4j + AJAX (III)<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYfqzg46eGUHfuEtOKddfSoEVDWGYctFM6rqT_pyaGsqNrsExAuByUO1jPPpJLdB6IypViZSLzzEtyVq5V3IM14nN81nIF9gNU1SfVAU-ZG3vjfVFw_UIqotdaCZjOnmKcd5iEaX6dKd0/s1600-h/web_1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 51px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYfqzg46eGUHfuEtOKddfSoEVDWGYctFM6rqT_pyaGsqNrsExAuByUO1jPPpJLdB6IypViZSLzzEtyVq5V3IM14nN81nIF9gNU1SfVAU-ZG3vjfVFw_UIqotdaCZjOnmKcd5iEaX6dKd0/s400/web_1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5367223306199311378" /></a><br />
<br />
<p><br />
Hola a todos,<br />
<br />
Como les contaba en los <b>Post anteriores</b> (<a href="http://getgeeks.blogspot.com/2009/08/strus2-log4j-ajax.html" target="_blank">post 1</a>, <a href="http://getgeeks.blogspot.com/2009/08/strus2-log4j-ajax-ii.html" target="_blank">post 2</a>), la nueva versión de Struts (Struts2) es muy diferente a su predecesor.<br />
<br />
<b><i>[si es primera vez que ves este post te recomiendo visitar los post anteriores]</i></b><br />
</p><br />
<br />
<span id="fullpost"><br />
<p><br />
Es por esto que voy a explicar en más detalles cómo funciona y configura este framework.<br />
Para ésto me basaré en el proyecto Struts2 publicado en el <a href="http://groups.google.com/group/getgeek?hl=es" target="_blank">Grupo de Google</a> (archivo: MVCStruts2.rar).<br />
<br />
Lo primero que se debe hacer es editar el descriptor de despliegue (archivo web.xml) para añadir el filtro que permite que Struts2 pueda ejecutarse en nuestro proyecto.<br />
Nuestro web.xml debiese quedar así:<br />
<pre class="brush: xml;"><?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>MVCStruts2</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
</pre><br />
<br />
De esta manera el servidor web (Tomcat en éste caso) sabrá que cualquier petición realizada debe pasar por el filtro FilterDispatcher, el cual es el <i>Controlador</i> de nuesta aplicación Web.<br />
<br />
Struts2 nos permite crear un archivo xml de configuración, en el cual podemos especificar qué debe hacer nuestro <b><i>Controlador</i></b> según la petición recibida por parte del cliente. Este archivo se llama struts.xml y debe crearse en package por defecto del proyecto Web Resources:src.<br />
El archivo del proyecto podemos escribirlo de la siguiente manera:<br />
<pre class="brush: xml;"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="login-config.xml" />
</struts>
</pre><br />
<br />
Como se puede apreciar prácticamente no hay nada de contenido en archivo, esto es porque se está utilizando un tag xml llamado <b>include</b>, el cual permite importar el contenido de otros archivos de configuración xml struts2. De esta forma evitamos que a medida que nuestra aplicación crezca, lo haga al mismo ritmo nuestro archivo struts.xml. Ahora veamos el contenido del archivo <b>login-config.xml</b> (el cual contiene las acciones de login de nuestra aplicación).<br />
<pre class="brush: xml;"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="accesopackage" extends="struts-default">
<action name="login" method="validarUsuario" class="cl.struts2.login.action.LoginAction">
<result name="success">/WEB-INF/home/home.jsp</result>
<result name="error">/WEB-INF/index.jsp</result>
</action>
<action name="logout" method="cerrarSessionUsuario" class="cl.struts2.login.action.LoginAction">
<result name="success">/WEB-INF/index.jsp</result>
</action>
</package>
</struts>
</pre><br />
<br />
Este archivo lo único que nos dice es que se ejecute la clase 'cl.struts2.login.action.LoginAction' y el método 'validarUsuario()' cuando llegue la acción 'login', y la misma clase pero el método 'cerrarSessionUsuario()' cuando llegue la acción 'logout'.<br />
En la acción 'login', si la ejecución del método es correcta se retornará la acción SUCCES, la cual nos llevará a la página '/WEB-INF/home/home.jsp', en caso contrario o ante un ERROR nos llevará a la página de inicio '/WEB-INF/index.jsp'.<br />
<br />
Ahora podemos crear nuestra página index.jsp la cual hará de login de usuario y llamará a la acción 'login'.<br />
<pre class="brush: html;"><%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Ingresar al sistema</title>
<link rel="stylesheet" href="estilos/estilos.css" type="text/css" />
<script type="text/javascript" language="javascript">
function validar(){
var user = document.form.username.value;
var pass = document.form.password.value;
if( user!=null && pass!=null ){
document.form.submit();
}
else{
alert("Ingrese usuario y contraseña");
}
}
</script>
</head>
<body>
<form method="post" name="form" action="login">
<table class="tabla">
<tr>
<td align="center" colspan="2" class="franja-titulo">
Ingresar al Sistema
</td>
</tr>
<tr>
<td class="texto">
Usuario:
</td>
<td>
<input type="text" name="username" id="username" class="campo-texto">
</td>
</tr>
<tr>
<td class="texto">
Contraseña:
</td>
<td>
<input type="password" name="password" id="password" class="campo-texto">
</td>
</tr>
<tr>
<td align="center" colspan="2" class="texto-tabla">
<%
if( request.getAttribute("error")!=null ){
%>
Error al validar los datos
<%
}
%>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="button" value="Aceptar" onclick="validar();">
</td>
</tr>
</table>
</form>
</body>
</html>
</pre><br />
<br />
Como se puede ver en la imagen, el formulario web de index.jsp redireccionará a la acción 'login'.<br />
Por lo tanto ahora veamos el código de nuestra clase 'cl.struts2.login.action.LoginAction'.<br />
<pre class="brush: java;">public class LoginAction extends ActionSupport implements ServletRequestAware,ServletResponseAware{
private static final long serialVersionUID = 1L;
private Logger logger = Logger.getLogger( LoginAction.class );
private HttpServletRequest request;
private HttpServletResponse response;
public String validarUsuario(){
if( SessionUtil.existeSession(request, SessionUtil.SESSION_USUARIO) ){
logger.debug("[validarUsuario] usuario ya validado");
return SUCCESS;
}
String username = request.getParameter("username");
String password = request.getParameter("password");
logger.debug("[validarUsuario] se reciben parametros: {usuario = " +username+ ", password = " + password +"}");
Usuario usuario = null;
if( username!=null && password!=null ){
logger.debug("[validarUsuario] se valida usuario");
Usuario usu = new Usuario();
usu.setUsername( username );
usu.setPassword( password );
ServicioUsuarios servicio = new ServicioUsuarios();
usuario = servicio.obtenerUsuario(usu);
}
if( usuario!=null ){
logger.debug("[validarUsuario] validacion correcta");
SessionUtil.crearSession(request, SessionUtil.SESSION_USUARIO, usuario, 15);
return SUCCESS;
}
SessionUtil.cerrarSession(request);
request.setAttribute("error","1");
logger.debug("[validarUsuario] error al validar usuario");
return ERROR;
}
public String cerrarSessionUsuario(){
logger.debug("[cerrarSessionUsuario] Cerrar session de usuario");
SessionUtil.cerrarSession(request);
return SUCCESS;
}
public HttpServletRequest getServletRequest() {
return this.request;
}
public HttpServletResponse getServletResponse() {
return this.response;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
</pre><br />
<br />
En el código se puede ver la clase LoginAction y su método validarUsuario(), el cual se ejecutará con la acción 'login'. No voy a explicar en detalle el contenido de este método (ya que con el material publicado <a href="http://getgeeks.blogspot.com/2009/08/strus2-log4j-ajax-ii.html">anteriormente</a> no debiese haber problemas para entender ésto ;)), pero se entiende que de alguna manera valida el usuario y password del usuario. Si la validación es correcta retornará la acción SUCCES, en caso contrario ERROR (si tienes dudas con ésto vuelve a ver la foto del archivo login-config.xml).<br />
<br />
Más adelante se detallará cómo funcionan los interceptores y cómo se ejecutan las llamadas AJAX.<br />
<br />
Atento a sus dudas o consultas.<br />
Saludos.-<br />
<br />
</p><br />
</span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com1tag:blogger.com,1999:blog-642435085995512969.post-56510934999445289892009-08-07T10:00:00.001-04:002009-08-12T13:19:21.904-04:00Frases: Diseño de Software"Hay dos formas de diseñar software: la primera es hacerlo tan simple que obviamente no hay deficiencias y la segunda es hacerlo tan complicado que no hay deficiencias obvias. La primera forma es mucho más difícil."<br /><br /><a href="http://es.wikipedia.org/wiki/C._A._R._Hoare" target="_blank">--C.A.R. Hoare</a><br /><br /><br />visto en: <a href="http://www.hackification.com/2008/12/23/a-double-handful-of-programming-quotes/">hackification</a>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com1tag:blogger.com,1999:blog-642435085995512969.post-41596223035452625672009-08-06T01:15:00.001-04:002009-08-17T09:25:52.243-04:00J2EE: Strus2 + log4j + AJAX (II)<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSkJfJ_lrFU8PP3CoPLReO5WdgrnrP3P3mWcG7nHVt18iGhM_ElWgivVtb6ptjD1kEjAc7yewItwfFc3ijCX_aPKgwV7V5OKWJR3vAEaVZlZ4uYdiLWSQ2H3Z5RZ2rvuAltVuRPOb9dZw/s1600-h/web_java_1_.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 51px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSkJfJ_lrFU8PP3CoPLReO5WdgrnrP3P3mWcG7nHVt18iGhM_ElWgivVtb6ptjD1kEjAc7yewItwfFc3ijCX_aPKgwV7V5OKWJR3vAEaVZlZ4uYdiLWSQ2H3Z5RZ2rvuAltVuRPOb9dZw/s400/web_java_1_.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5366715280697770114" /></a><br /><br /><p><br />En el <a href="http://getgeeks.blogspot.com/2009/08/strus2-log4j-ajax.html" target="_blank">post anterior</a> se mostró los distintos frameworks utilizados para desarrollar un proyecto Web Java, el cual puede ser descargado desde el <a href="http://groups.google.cl/group/getgeek/files?hl=es" target="_blank">Grupo de Google</a> (archivo: MVCStruts2.rar).<br /></p><br /><br /><span id="fullpost"><br /><p><br />A continuación explicaré la arquitectura del proyecto y cual es la función de cada un de los componentes de éste.<br />En esta imagen podemos ver el diseño arquitectónico del sistema.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4f7aQ9fLAora0bYHEYzA49zJbGJsz3SRdJsypk2avneul1e7T82cUXH7e5NWAvOliahZpQnBTD2swGBaywez0csBNBVsbimhNYzsVUjT578huYeU5HikGjeebpw2Fhdk0Q0g3JtPPzYY/s1600-h/arquitectura.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 261px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4f7aQ9fLAora0bYHEYzA49zJbGJsz3SRdJsypk2avneul1e7T82cUXH7e5NWAvOliahZpQnBTD2swGBaywez0csBNBVsbimhNYzsVUjT578huYeU5HikGjeebpw2Fhdk0Q0g3JtPPzYY/s400/arquitectura.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5366715890581040162" /></a><br />Esta imagen muestra cómo es la división arquitectónica de la aplicación, muestra claramente cómo se aplica el patrón MVC. Además da a conocer el flujo y la forma en que se comunican los distintos componentes que participan en el sistema.<br /><br />A continuación se definirán los distintos tipos de clases que constituyen el sistema:<br /><br /><b>HTML y JSP:</b> Básicamente son las páginas Web que muestran gráficamente el sistema al usuario. Los usuarios al ejecutar funciones sobre las páginas Web (capa vista) generan eventos, los cuales son capturados por el <b>Controlador</b>.<br /><br /><b>Controlador:</b> Es el intermediario entre la capa Vista y la capa Modelo, obtiene los eventos realizados por el usuario en la capa Vista y ejecuta la acción (<b>ActionClases</b>) correspondiente en el Modelo, la cual responderá a la solicitud realizada por el cliente. El controlador está constituido por los archivos de configuración XML (struts.xml) que son interpretados por el framwork Struts2.<br /><br /><b>InterceptorClases:</b> Son clases que heredan de la interfaz Interceptor que proporciona el framework Struts2. Su función es interceptar las invocaciones que realiza la capa vista sobre el controlador para invocar a las <b>ActionClases</b> (y viceversa), durante ésta interrupción éstas clases pueden realizar validaciones (ejemplo: validar sesión de usuario), etc. y si ésta es correcta el flujo o acción se realiza normalmente.<br /><br /><b>ActionClases:</b> Heredan de la clase ActionSupport proporcionada por el framework Struts2. Su función (en éste proyecto) es validar la integridad de los datos recibidos e invocar a los diversos <b>Servicios</b> los cuáles le proveerán de la información necesaria para retornar la respuesta requerida por la capa Vista.<br /><br /><b>Servicios:</b> Son clases de negocio, las cuáles pueden obtener datos a través de la invocación a diversas <b>ClasesDAO</b>, procesarlos y devolver la información solicitada por la capa Web.<br /><br /><b>ClasesDAO:</b> Estas clases acceden "directamente" a diversos orígenes de datos (Bases de datos, archivos de texto).<br /><br /><b>ClasesTO:</b> Estas clases proporcionan objetos de transferencia, los cuales "viajaran" a través de la aplicación. Por ejemplo: una clase DAO consultará un origen de datos, y retornará un lista de objetos TO.<br /><br /><b>ClasesUtil:</b> Son clases utilitarias que proporcionarán funciones que podrán ser utilizadas por todos los componentes del sistema.<br /></p><br /></span>egaclhttp://www.blogger.com/profile/13799041018079225733noreply@blogger.com4