viernes, diciembre 19, 2008

Si los lenguajes de programación fueran religiones

Vía http://www.pragprog.com, encuentro un articulo que comenta los lenguajes como si fueran religiones, realmente es muy divertido, me gusta en especial la definición de Perl (sangre de cabra y trabajos un Viernes a las 21 h), el de Ruby, C# y VB también están muy buenos.

Hecheles un OjO y que se diviertan!

jueves, diciembre 18, 2008

Guía de supervivencia para Maven

Maven Guía rápida


Este documento no pretende ser una guía completa a Maven, solo una guía rápida para poder

iniciarse en Maven y consecuentemente, continuar por cuenta propia hacia características más

avanzadas.



Que es maven?


Maven es una herramienta open source, mediante la cual podemos administrar ciertas etapas del

ciclo de vida de nuestros proyectos, entre variadas cosas más.

Para darnos un ejemplo, con maven podemos compilar nuestros componentes, deployarlos,

correr nuestros casos de pruebas, etc.



Pero acaso no puedo hacerlo con Ant?



Correcto, gran parte de las cosas que se pueden realizar con Maven, pueden implementarse con

Ant, sin embargo podemos pensar en Ant como una herramienta de más bajo nivel, solo por citar

un breve ejemplo, con maven podemos ejecutar la siguiente instrucción:


mvn clear




Esta simple instrucción elimina los directorios donde tenemos deployado nuestro proyecto, muy

útil por ejemplo cuando queremos deployar desde cero nuestro proyecto nuevamente. En Ant

para implementar esta funcionalidad deberíamos realizar un "task" y después buscar los tareas

Ant necesarias para eliminar ciertos directorios. Así pues, podríamos ver a Maven como una

serie de componentes al estilo Ant, pero que ya se encuentran implementados y lo único que

espera es contar con cierta estructura estándar para realizar las operaciones, además de ciertos

parámetros en algunas ocasiones, esto nos lleva a otro punto importante en Maven, el patrón de

estructura de directorios.



Estructura de patrones: Convención vrs Configuración


Un termino acuñado en boga últimamente es utilizar convención en vez de configuración,

ejemplos como Ruby on Rails, han disparado y demostrado la eficiencia de utilizar estructuras

patronicas, en vez de expresar directamente todo en la meta información, así pues nos basamos

en convenciones esperadas, para realizar diferentes acciones.


Maven no escapa a este movimiento, es así como Maven logra compilar, deployar entre muchas

otras tareas disponibles, sin necesidad de que le indiquemos donde se encuentran nuestros

archivos fuentes, recursos, archivos Web, etc.


Maven asume que nosotros contamos con una estructura como esta, por ejemplo:


${basedir}/src/main/java

${basedir}/src/main/resources

${basedir}/src/test/java

${basedir}/src/test/resources


Estos directorios le indica a Maven, donde encontrar nuestros archivos Java, los diferentes

recursos como archivos de "properties", "xmls", entre otros. La carpeta "test" por su parte le

indica a Maven donde se encuentran los archivos "java" y los "recourses" necesarios para las

pruebas de unidad; por ejemplo nosotros podemos tener cargadas configuraciones y classpaths

diferentes a la hora de ejecutar nuestros casos de pruebas.



Artefactos


Los artefactos en Maven, los podemos ver como un tipo de proyecto o componente, Maven

maneja gran variedad de artefactos y dependiendo del tipo que sea nuestro proyecto actual (el

tipo de artefacto se puede ver como una plantilla que Maven ya tiene lista para utilizarla), la

estructura de carpetas básica mencionada en el punto anterior puede extenderse y la forma en que

se deploya puede resultar diferente, por ejemplo cuando el artefacto es un "web-app",

adicionalmente se nos crea una carpeta en:


${basedir}/src/main/webapp


Donde depositamos todos los recursos Web, incluyendo nuestra carpeta "WEB-INF", de igual

manera para los diferentes artefactos dispondremos de variadas estructuras de carpetas agregadas

a la composición básica, antes mencionada.



Manejo de dependencias y repositorios


Maven proporciona un modulo para el manejo de dependencias, ya veremos mas adelante de que

se trata esto del manejo de dependencias, sin embargo por ahora solo mencionar que Maven tiene

un repositorio donde almacena nuestros componentes o componentes de terceros, por ejemplo

los archivos jar de Struts, los archivos jar de Apache Commons, etc. Por defecto el repositorio es

almacenado en un directorio local, regularmente en ${userprofile}/.m2. En este repositorio como

en todos se almacenan los jar, por artefact id y versión. Adicionalmente resulta importante

mencionar que Maven tiene la posibilidad de utilizar directorios compartidos en una Intranet, por

ejemplo, un servidor local donde se podrían almacenar los componentes de la compañía y

compartirlos, al estilo de Framework o librerías de utilidades.


Maven, además cuenta con un gigantesco repositorio (http://repo1.maven.org/maven2/) expuesto

en Internet de donde bajamos la versiones de los diferentes componentes, regularmente nosotros

podemos indicarle a Maven los repositorios que deseamos utilizar, mas adelante cuando se

explique el manejo de las dependencias, entenderemos de mejor manera, el manejo de los

repositorios.



Proyectos


Como hemos mencionado, Maven maneja los proyectos como artefactos y estructuras patronicas

para los directorios, la forma en como Maven conoce la minima meta información de nuestro

proyecto, es mediante el Project Object Manager (POM), este es un archivo XML, alojado en la

raíz de nuestro directorio de proyecto con el nombre de pom.xml.



Creando nuestro primer proyecto



Para crear nuestro primer proyecto necesitamos indicarle a Maven un "groupId", un "artifactId" y

un paquete Java por defecto. El siguiente ejemplo nos muestra como crear el proyecto,

"primerproyecto", con un paquete por defecto "cr.co.jsanca.mavenexample".


mvn archetype:create -DgroupId=cr.co.jsanca -DartifactId=primerproyecto

-DpackageName=cr.co.jsanca.mavenexample


El "groupId", le indica a Maven el identificador de grupo bajo el cual queremos agrupar nuestros

componentes, una buena práctica es agrupar todos los componentes de nuestro proyecto o

compañía bajo un mismo "groupId". Por ejemplo en un proyecto clásico podríamos tener:


mvn archetype:create -DgroupId=cr.co.jsanca -DartifactId=dao -DpackageName=cr.co.jsanca.dao

mvn archetype:create -DgroupId=cr.co.jsanca -DartifactId=service -DpackageName=cr.co.jsanca.service

mvn archetype:create -DgroupId=cr.co.jsanca -DartifactId=action -DpackageName=cr.co.jsanca.action


Las anteriores líneas indican a Maven crear un proyecto dao, service y action bajo el mismo

grupo y con los paquetes Java cr.co.jsanca --> dao, service, action.




El "artifactId", le indica a Maven el identificador especifico del proyecto dentro del group id, así

pues la llave para localizar un proyecto es el group id y el artifact id, con estos dos datos

podemos bajar alguna de las versiones disponibles.




Después de crear nuestro primer proyecto podemos ir a nuestro espacio de disco y comprobar los

siguientes archivos:



primerproyecto

  • pom.xml

  • main

    • java

      • cr/co/jsanca/mavenexample/App.java





  • test

    • java

      • cr/co/jsanca/mavenexample/AppTest.java






Como notarán esta es la estructura minima para crear nuestro proyecto de Maven, en nuestro

caso aun no contamos con archivos de recursos, algo importante de anotar es que dentro del

directorio "java" tanto de main y test, Maven solo espera archivos .java, así que el resto de los

archivos que coloquemos no los va tomar en cuenta a la hora de compilar y deployar, por esa

razón que ocupamos crear la carpeta "resources", igual aquí podes crear paquetes Java que se

verán reflejados cuando deployemos nuestro aplicación.



Construyendo nuestro primer proyecto


Como mencionamos anteriormente, Maven nos va ayudar para controlar nuestro ciclo de vida,

por ejemplo si queremos compilar nuestro proyecto, simplemente debemos ejecutar:


mvn compile


Si vamos a la carpeta donde tenemos nuestro proyecto, nos daremos cuenta que tenemos una

carpeta llamada "target", es en esta carpeta donde se almacenan todos los archivos deployados,

.class, .jar, .war, .ear, entre otras cosas que puede deployar maven.


En el caso de nuestro "primerproyecto", la única carpeta con que contamos es "classes" y

contiene el compilado de la clase App.java.


Entre otras funcionalidades que nos proporciona Maven, tenemos:


mvn test


Esta tarea corre nuestro test, por defecto son unit test, de JUnit sin embargo y muy

probablemente existan formas de utilizar otros frameworks.


mvn clear


Esta tarea limpia (elimina) todo el contenido de la carpeta "target", para realizar un compilado,

empaqueta o deployado desde cero.


mvn package


Esta tarea compila, ejecuta los test y empaqueta nuestro proyecto ya sean en .jar, .war o .ear.


mvn install


Esta tarea compila, ejecuta los test y empaqueta nuestro proyecto y adicionalmente lo instala en

el repositorio, para que pueda ser referido como dependencia, por otros proyectos.


mvn deploy


Esta tarea compila, ejecuta los test y empaqueta nuestro proyecto, adicionalmente lo sube a

nuestro servidor o repositorio (tenemos que indicarlo en el pom) para que el ejecutable pueda ser

compartido para otros desarrolladores, en algunas ocasiones uno redirecciona el contexto del

App Server a lo empaquetado en la carpeta "target" de esta manera nos basta con solo hacer un

"package".


mvn site


Esta simpática tarea, genera un sitio con la documentación del proyecto.



Paseando por nuestro POM


Abrimos nuestro archivo POM.XML, y veremos el siguiente contenido:



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cr.co.jsanca</groupId>
<artifactId>primerproyecto</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>primerproyecto</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Esta es la configuración por defecto que tenemos, para el proyecto. Vamos analizarlo a
continuación,

ModelVersion, es la versión de la especificación del modelo Maven.
GroupId, actifactId ya los hemos abordados.
Packaging, indica a Maven la forma en que debe empaquetar el proyecto.
Version, indica la versión del build de nuestro projecto.


Dependencies, esta sección es muy importante pues indica a Maven cuales son las dependencias

principales de nuestra aplicación, como se puede notar lo que estamos declarando es una

dependencia hacia otro proyecto Maven, en nuestro caso al proyecto junit, del grupo junit,

versión 3.8.1. El "scope" es utilizado en algunas ocasiones para denotar si esta la naturaleza de la

dependencia, veamos los posibles valores:


compile, este es el scope por defecto y se utiliza para el proceso de compilación.




provided, este dependencia se incluye en tiempo de compilación, pero se omite a la hora de

empaquetar, pues se asume que el JDK o el Server lo contiene, por ejemplo los jar de server api

en Tomcat.




runtime, indica que esta dependencia no es necesaria para compilación pero si para ejecución, tal es el caso de un Driver de JDBC o cualquier componente que se invocado solo por reflexión.


test, esta dependencia solo es utiliza para compilar y ejecutar los fuentes bajo la carpeta test.


Algo importante a considerar en las dependencias es la transitividad de las misma, con

transitividad queremos decir que si una dependencia a la vez depende de otra y esta de otra, etc,

todas estas dependencias serán agregadas cuando empaquetemos nuestro proyecto (package).


Por ejemplo, si incluimos la librería A, y esta depende de B y C


A -> B, C.


Cuando deployemos nuestra aplicación encontraremos bajo “lib” todas las librerias:


lib


  • A

  • B

  • C




Plugins



Los plugins son un mecanismo mediante el cual escalamos la funcionalidad por defecto que

proporciona maven, un plugin puede ser un componente contenido dentro del mismo Maven o

puede ser un componente de terceros, el cual Maven busca en el momento de utilizarlo y lo baja

localmente para utilizarlo, los plugins sirven para cumplir variadas tareas, tales como; indicar en

que compliance queremos compilar nuestro código (5.0, 6.0, etc), como empaquetas y deployar

nuestras aplicaciones, como limpiar el target, correr aplicaciones de terceros como tareas Ant,

plugins de Hibernate para generar nuestra base de datos, de WebServices, para deployar nuestros

Stubs, etc.


A continuación unos ejemplos de plugins:


<plugin>

<artifactId>maven-compiler-plugin</artifactId>

<configuration>

<source>1.5</source>

<target>1.5</target>

</configuration>

</plugin>


Plugin para indicarle a maven, que tanto el código fuente de nuestra aplicación, así como los

compilados, son Java 5.


<plugin>

<artifactId>maven-war-plugin</artifactId>

<configuration>

<webappDirectory>target/war/survey</webappDirectory>

</configuration>

</plugin>


Este plugin le indica a Maven que el directorio donde debe deployar la aplicación Web, es

"target/war/survey".


De manera identica puedes agregar diferentes tipos de plugins y los mismo son datos por Maven

o los fuentes terceras.




Repositorios


Los repositorios son útiles para indicarle a Maven, de donde debe bajarse los diferentes

artefactos, por ejemplo se pueden indicar servidores de open source, servidores a nivel de

intranet, etc. Los repositorios se pueden indicar de la siguiente manera:


<repositories>

<repository>

<id>repo1</id>

<name>Maven Central Repository</name>

<url>http://repo1.maven.org/maven2</url>

</repository>

<repository>

<id>java.net</id>

<url>http://download.java.net/maven/2</url>

</repository>

</repositories>


Aquí le indicamos a Maven que busque en los repositorios repo1 y java.net los diferentes

artefactos.



Conclusiones


Maven es una excelente herramienta que nos ayuda en diferentes ciclos de vida de nuestra

aplicación, de una forma muy sencilla.


Maven tiene un manejo de dependencias, que facilita mucho el estar buscando información

acerca de cuales jar ocupa un Framework o librería, encontraste, nuestra aplicación puede

inflarse mucho, por incluir jar de funcionalidades de un Framework que no ocupamos por

ejemplo, pero son incluidas.


Maven es una herramienta muy escalable y configurable, se puede integrar con los frameworks

más populares entre otras cosas.


http://maven.apache.org/


martes, diciembre 16, 2008

La fábula del pastor y el PM

Interesante y reflexivo cuento, acerca de un pastor y un PM..
Personalmente opino que el role, de los Manager hoy por hoy, es el de facilitadores, negociantes y reconciliadores. Al final lo importante es sacar un buen producto y no que cumplas un horario o vistas saco y corbata.
Muchos PM me parece, pierden las perspectiva creyéndose los dueños de la compañía y olvidan que su labor es llevar los proyectos a buen fin y no maximizar las ganancias de la compañía mediante la aplicación de despotas policitas pasadas de moda. Una compañía que tiene proyectos exitosos, va tener mas demanda de proyectos por parte de los clientes y por ende maximizará de mejor manera su capital, a través de tarifas mas favorables, por trabajo de mayor calidad o la producción de proyecto en mayores cantidades.

domingo, diciembre 14, 2008

Labor de mantenimiento Upd# 2

En esta nueva actualización del blog a parte de los comunes post, se han agregado mas links y blogs, también se han adherido soporte para Google analytics, para llevar las estadísticas del sitio. También se ha agregado el primer álbum de fotos, como parte de la entrega de arte del CowParade, en la provincia de Heredia, específicamente en el parque Central del Cantón, por si deseas checkarla.

Saludos

El gallito ingles


Hoy me puse a pensar acerca varios hechos que me hacen mucha gracia acerca de nuestra cultura y el uso del idioma ingles.




El primer punto que deseo comentar es relativo a los extranjeros, en nuestro país se tiene la costumbre de pensar que todo gringo o europeo es turista y debemos hablar, ingles, chino o portugués a la hora de dirigirnos a él, por ejemplo; si nos encontramos un gringo en la calle que no logra ni sincronizar los labios para decir "hola", la gente le habla en ingles (si puede hacerlo), mas en cambio si vamos a U.S.A, en calidad de turistas y entramos por ejemplo al aeropuerto o a una tienda de comida rápida como Subway, o BK y no hablamos ingles o no entendemos el rápido ingles de un empleado de color negro de Atlanta por dar un ejemplo, el mismo empleado al que se le esta pagando para que nos de un servicio, se molesta y se estresa que no sepamos perfecto ingles, será que los ticos somos muy buena nota o de lo contrario por que no aplicar la misma regla, se molestaran nuestros "turistas"?




Otro punto, es la gente que regularmente, aunque no siempre, trabaja en un call center y va a lugares publicos, tales como; buses, bares, etc, y se pone con el compañero hablar en ingles y en un tono de voz altísimo para hacerse notar, toda una polada si me preguntan y además que tiene de malo el español, es cool.





Mi tercer punto, se va a referir a los correos en ingles. En compañias internacionales, donde los clientes son extranjeros, en su mayoría con el ingles como idioma nativo, el enviar correos en ingles resulta obligatorio, sin embargo la comunicación interna, de tico a tico, resulta ridiculo que tenga que hacerse en ingles, algunas veces alegan que es por razones de auditoría, pero no siempre aplica, la invitación a una fiesta por ejemplo, a quien le va interesar auditarla???





Por ultimo, quiero referirme a los gringos que viven y se han establecido en CR, gente si a Roma fueramos como romanos actuaremos, manda que con años de vivir en CR, no puedan ni siquiera entablar una discusión tarzanica en español, por favor, si uno se queda con solo el idioma español en Inglaterra o USA; de fijo se muere de hambre, como hace esa gente para vivir aquí, es que manda huevos, al menos deberían hacer el minimo esfuerzo....



En fin, que opinas, estoy fuera de lugar o tengo algo de razón? Yo creo que tenemos que tener más amor por lo nuestro, incluyendo por supuesto, el idioma.

sábado, diciembre 13, 2008

Lectura en progreso

En este post, solo quiero comentarles acerca de algunos libros que estoy leyendo y mis impresiones acerca de los mismos:





Java Persistance with hibernate, a mi parecer es el mejor libro para aprender hibernate desde el punto de vista de JPA. El libro a pesar de ser muy denso, no deja de ser interesante y muy útil.
Si deseas aprender, JPA implementado con Hibernate, este es tu libro.









Java, Como programar de Deitel y Deitel es un clásico, para aprender a programar basándose en Java, el libro me parece muy básico, aunque tiene temas muy interesantes como Java NIO y Java Image, entre otros, lo uso como material de referencia para un curso de Java básico que estoy dando en avVenta.








MySQL para Windows y Linux, es un interesante libro, tanto para aprender las nociones básicas de SQL como para aprender tópicos intermedios de MySQL, lo llevo bastante avanzado y me parece bastante bien.






Groovy Recipes, en mi afán por aprender Groovy, este libro ha sido una excelente herramientas para conocer lo básico, tiene un capitulo introductorio a grails y esta enfocado a programadores Java que desean agregar Groovy a su caja de herramientas.






Miro, uno de mis pintores favoritos, por su fuerza, intensidad y originalidad en los colores. Este referencia visual, me ha gustado mucho, aunque la lectura en forma de crónica, no es lo que esperaba, hubiera preferido mas opiniones acerca de los cuadros, sin embargo no me deja de gustar, bonito libro.








La cuidad de las bestias, guau, es lo que puedo decir, la primera de 3 tres tomos, acerca de la historia de Alexander Cold y su abuela, a traves de grandes aventuras, Isabel Allende sin duda alguna es una de las mejores escritoras latinas y su verso, es tan educativo como emocionante.

viernes, diciembre 05, 2008

Opinión Servlet 3.0

Leo en el sitio The Server Side, un articulo que da un pequeño recorrido a través de la nueva especificación de Servlets que esta por salir. Como se había escuchado y era de esperar, los Servlets podrán ser creados como Pojos, digamos:

@Servlet(urlMapping={"/myServlet"}, name="MyServlet")
class MyServlet {

@GET
@POST
public void handleRequest(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
....
}
}

Yo le encuentro algunos problemas a esto:

  • No se desacopla del WebContainer o de los objectos Mock para hacer testing, por que se sigue recibiendo el objeto request y response.

  • En caso que ocupe los "init" parámetros o algún método del HTTPServlet, no veo ninguna alternativa

  • Como dice el articulo de ServerSide, un usuario puede anotar dos veces un método con GET o POST, provocando una posible confusión al WebContainer



La primera característica comentada en el articulo, me parece cool, en el sentido que te proporciona un control mas tipo HTTP 1.1 para los request, controlando los hilos del request.

La segunda también esta cool, sin embargo me gustaría que esta característica pudiera ser desconectada cuando una aplicaron es desplegada, por asunto de seguridad, pues alguien podría subir un jar a nuestro classpath y desplegarlo de forma automática.

En fin, parece que los pojos anotados, están en boga y a la luz de los cambios, pienso que esta bien que estén ahí, pero no estoy seguro de querer usar todo el batiburrito con salsa agridulce que nos están dando :)

Link del articulo http://www.theserverside.com/tt/articles/article.tss?l=PonderingAboutJSR135

jueves, diciembre 04, 2008

Las patentes - un problema legendario



En este mundo, donde las personas que tienen el suficiente dinero quieren patentarnos hasta las ganas de comer (o descomer), donde el dinero y las leyes, se ponen a servicio de los milenarios millonarios, nos podemos remontar a un caso legendario; Mucha gente atribuye a Alexander Graham Bell el revolucionario invento del teléfono y por ende las telecomunicaciones, sin embargo y de forma muy injusta la historia olvido entre laureles la existencia del verdadero inventor del teléfono; el Italiano Antonio Meucci, quien por preocupaciones económicas, nunca pudo patentar el aparato.
Sin duda, esto nos da una pequeña idea de como, las personas que tienen dinero siempre han intentado patentar la creatividad e imaginación, de los economicamente menos afortunados, cuantos pequeños pero revolucionarios científicos habrán hecho mas ricos, a IBM, Microsoft y Apple, a cambio de migajas comparandolas con las ganancias que estos gigantes obtienen.
En fin, creo que las patentes fueron diseñadas para defender el esfuerzo y reconocer la creación de los inventores, pero como muchas cosas, siempre existe un abogado que sepa poner las leyes a favor del capital y que saque su buena tajada.

Bibliografía:
http://www.josepino.com/discover/?who_invented_telephone
http://www.wisegeek.com/was-alexander-graham-bell-the-real-inventor-of-the-telephone.htm

lunes, diciembre 01, 2008

Checkando el marchamo

Bueno, para los que tenemos que pagar marchamo, aquí lo pueden consultar en línea:

http://portal.ins-cr.com/DCI.SIR.Web/frmPagoMarchamos.aspx

Pura vida!

domingo, noviembre 30, 2008

Ley contra el SPAM

Leo en el periodo la Nación (http://www.nacion.com/ln_ee/2008/noviembre/28/pais1788837.html) la divulgación acerca de una ley para castigar a las entidades o personas que realicen SPAM, ya sea mediante llamadas telefónicas, mensajes de texto (SMS), etc.

Una buena practica, cuando recibimos un correo electrónico basura, es rastrear la IP y enviársela a Racsa detallando el delito, en el caso de mensajes de texto o llamadas no deseadas, se puede notificar al ICE.

Por otro lado, sería interesante crear un "black list", para denunciar y exponer a los sitios, números de teléfono o personas que se dedican a este tipo de actividades.

miércoles, noviembre 26, 2008

Impensando acerca de las referencias en Java

Fue hace ya algún tiempo que pase un rato discutiendo con algunos compañeros acerca de si existe o no el paso por referencia; el discurso fue mucho hacia que en Java el comportamiento, en el supuestamente pasamos por referencia un objeto y por valor los objetos primitivos creo mucha polémica.

Para ubicarnos en contexto veamos el siguiente ejemplo.

public static void main(String[] args) {

int value = 10;

changeValue(value);

System.out.println("value = " + value);

User user = new User();
Name name = new Name();

user.setName(name);
name.setName("jsanca");
name.setLastName("XXX");

user.setPassword("123queso");

System.out.println("user: " + user.getName().getName() + ", "
+ user.getName().getLastName() + ", " + user.getPassword());

changeValue1(user);

System.out.println("user: " + user.getName().getName() + ", "
+ user.getName().getLastName() + ", " + user.getPassword());

changeValue2(user);

System.out.println("user: " + user.getName().getName() + ", "
+ user.getName().getLastName() + ", " + user.getPassword());

changeValue3(user);

System.out.println("user: " + user.getName().getName() + ", "
+ user.getName().getLastName() + ", " + user.getPassword());
}


// lost the reference
private static void changeValue3(User user) {

Name name = new Name ();
name.setName("anotheruser");
name.setLastName("somelastname");
user = new User (); // here lost the reference.
user.setPassword("xxxxxx");
}

// change the password, used reference for user object.
private static void changeValue2(User user) {

user.setPassword("654321");
}

// change the name for new name object, used reference for user object.
private static void changeValue1(User user) {
Name name = new Name ();
name.setName("hackuser");
name.setLastName("trocker");

user.setName(name);
}

private static void changeValue(int value) {

value *= 20;
}

Resultado:

value = 10
user: jsanca, XXX, 123queso
user: hackuser, trocker, 123queso
user: hackuser, trocker, 654321
user: hackuser, trocker, 654321

Como se puede notar, cuando pasamos un valor primitivo (llamese entero, carácter, etc) y el valor se modifica en el método, el resultado no se refleja al salir del "scope" del método, de aquí le recomiendo pasar los valores primitivos como final y así se asegura que los programadores no van a tener confusiones.

El segundo y tercero método, consiste en la supuesta referencia y la misma es modificada, la tercera pierde la referencia, pues cuando se realiza un "new" el compilador otorga una nueva casilla de memoria, perdiendo totalmente la referencia pasada por parámetro.

Si analizamos, por ejemplo C++, cuando una variable inclusive nula, se le pasa &miVar en un parámetro, realmente pasamos un referencia, pero esto sucede porque en C++ la memoria es gestionada por los programadores, al contrario de Java, donde es tarea del Garbage Collector; en C++ existen los punteros, así como las instrucciones new y delete o free y malloc en el caso de C, pero en Java no existen los punteros, por lo que discutir acerca si el paso por referencia es estrictamente igual que el que esperamos en C++ no tiene sentido, pues la referencias pueden solo existir en un lenguaje con soporte de punteros, al no tener Java esta característica, en realidad no existe el paso por referencia, solo podemos concluir que Java no cambia los datos primitivos en una función, pero puede cambiar las propiedades de un objeto siempre y cuando el objeto en si, no sea cambiado, es decir que no suceda como en el método "changeValue3()" donde se le realiza un "new" al objeto pasado por parámetro.

La unica excepción a esta regla, la podemos encontrar en el contexto de RMI, donde todos los objetos así como los primitivos son pasados por valor (por razones obvias de perfomance), aunque extendiendo una interface se le puede indicar que esta variable debe ser sincronizada entre el cliente y el server, es decir que se pase una referencia al estilo de Java.

martes, noviembre 25, 2008

Labor de mantenimiento

Como parte mi labor de mantenimiento, se han adherido nuevos elementos al blog;

  1. Se agrego un icono para el usuario de debugmodeon y mi perfil de linkedin.

  2. Se cambio el "look & feel" y la estrategia adSense.

  3. Se agrego un nuevo elemento llamado: Que hay de nuevo en blogger, el mismo tiene las actualizaciones mis blogs.

  4. La sección de visitalos fue actualizada y refactorizada.

  5. La sección de foto fue eliminada, por no contar con ninguna hasta el momento.



Del primer punto, solo decir que ambos iconos los tome del sitio debugmodeon y los agregue como un nuevo elemento HTML/JavaScript.

El segundo punto fue cambiado después de leer algunos artículos en adsense en español; este sitio además fue agregado a que hay de nuevo y les recomiendo visitarlo regularmente, pues contiene información y artículos muy interesantes acerca de Google AdSense.

El tercer elemento me gusta bastante y muestra de una manera muy agradable los blog con las entradas mas recientes.

Mi ultimo y cuarto elemento, he insertado y removido algunos links, ahí seguiré agregando links de interés común.

Espero les guste, ciao!

lunes, noviembre 24, 2008

Utilizando expresiones regulares en Java

A continuación muestro un ejemplo de como utilizar expresiones, no se pretende cubrir extensivamente ni mucho menos, el uso de expresiones regulares. Nuestro ejemplo, simplemente muestra como buscar los matches, de una cadena dentro de otra.

Nota: Tanto el objeto Pattern como Matcher, se encuentra alojados en el paquete java.util.regex del SDK Java Standard.

public static int countMatches (String string, String patternToFind) {

Pattern pattern = null;
Matcher matcher = null;
int countMatches = 0;

pattern = Pattern.compile(patternToFind);
matcher = pattern.matcher(string);

while (matcher.find()) {

countMatches +=1;
}

matcher = null;
pattern = null;

return countMatches;
} // countMatches

System.out.println(countMatches("hola ?,?,?,?,?)", "\\?"));
System.out.println(countMatches("hola)", "\\?"));

Resultado:

5
0

El ejemplo simplemente compila una cadena, una vez compilado y siendo valido, solicitamos los matches e invocamos a find, para ir buscando los matches de la cadena ahí.

Bastante simple, disfrutenlo!

Open CSV

http://opencsv.sourceforge.net/ trata de un framework muy simple y sin mas dependencias de acople que el mismo SDK, a continuación muestro como encapsular mediante Spring, la librería y a su vez leer un archivo csv.


import java.io.Closeable;
import java.io.IOException;

/**
* Common interface to read CSV file extension.
* @author jsanca
*
*/
public interface CsvReaderGenericDAO extends Closeable {

/**
* Return the next row in the CSV file,
* null if not has next.
* @return String []
*/
String [] next () throws IOException;
} // E:O:F:CsvReaderGenericDAO.

Esta clase será nuestra interface común para el lector de Csv. Como puedes ver, simplemente lee la siguiente fila y retorna un vector de cadenas, null en caso que ya no existan mas filas.

import java.io.IOException;

import au.com.bytecode.opencsv.CSVReader;

/**
* http://opencsv.sourceforge.net/ implementation wrapper.
* @author jsanca
*
*/
public class OpenCsvReaderGenericDAOImpl implements CsvReaderGenericDAO {

private CSVReader csvReader = null;

/**
* Constructor.
*/
public OpenCsvReaderGenericDAOImpl(CSVReader csvReader) {

this.csvReader = csvReader;
} // OpenCsvReaderGenericDAOImpl.

/* (non-Javadoc)
* @see cr.smartframework.geo.locator.dao.CsvReaderGenericDAO#next()
*/
@Override
public String[] next() throws IOException {

return this.csvReader.readNext();
} // next.

/* (non-Javadoc)
* @see java.io.Closeable#close()
*/
@Override
public void close() throws IOException {

if (null != this.csvReader) {

this.csvReader.close();
}
} // close.

} // E:O:F:OpenCsvReaderGenericDAOImpl.

Esta sería nuestra implementación, por defecto, implementa la interface antes dicha, junto con la interface closeable.
La implementación simplemente envuelve (wrappea) un CSVReader e invoca al método readNext, para ir obteniendo la siguiente fila.

import java.io.File;
import java.io.FileReader;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import au.com.bytecode.opencsv.CSVReader;

/**
* Factory to build the OpenCsvReader...
* Lee y parsea a objetos un archivo csv.
* @author jsanca
*
*/
public class OpenCsvReaderGenericDAOFactoryBean implements FactoryBean,
InitializingBean {

private OpenCsvReaderGenericDAOImpl object = null;

private String pathFile = null;

/**
* Obtiene el path del archivo csv.
* @return String
*/
public String getPathFile() {
return pathFile;
} // getPathFile.

/**
* Obtiene el path del archivo csv.
* @param pathFile String
*/
public void setPathFile(String pathFile) {
this.pathFile = pathFile;
} // setPathFile.

/**
* Constructor.
*/
public OpenCsvReaderGenericDAOFactoryBean() {

super ();
} // OpenCsvReaderGenericDAOFactoryBean.

/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
public Object getObject() throws Exception {

return this.object;
} // getObject.

/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@SuppressWarnings("unchecked")
@Override
public Class getObjectType() {

return OpenCsvReaderGenericDAOImpl.class;
} // getObjectType.

/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
@Override
public boolean isSingleton() {

return false;
} // isSingleton.

/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {

CSVReader csvReader = null;

csvReader = new CSVReader (new FileReader(new File (this.pathFile)));
this.object =
new OpenCsvReaderGenericDAOImpl (csvReader);
} // afterPropertiesSet.

} // E:O:F:OpenCsvReaderGenericDAOFactoryBean.

Ahora realizamos un acomple intrusivo para crear un factorybean de String, el mismo posse la propiedad "pathFile", donde se asigna (comunmente mediante inyección) la locación del archivo. Si hechas un ojo en "afterPropertiesSet"; este método simplemente crea un CSVReader.


<bean id="cvsReaderDAO" class="cr.smartframework.geo.locator.dao.OpenCsvReaderGenericDAOFactoryBean">
<property name="pathFile" value="${csvFilePath}">
</property>



<bean id="algunBean" class="AlgunBean">
<property name="cvsReaderDAO" ref="cvsReaderDAO">
</property>

Por ultimo mostramos el código necesario para asignar nuestro cvsReaderDAO a algún bean.

viernes, noviembre 21, 2008

Revisa tu ortografía

En los últimos días y como todos los blogueros se darán cuenta, el corrector ortográfico de blogger, no esta funcionando de la manera correcta, encontré este otro sitio donde puedes checar en línea tu ortografía; http://revisor.com.ar/, funciona bastante bien y es mejor que tener que abrir el open office o el Abi.

http://portableapps.com/

http://portableapps.com/ es un sitio Web, donde puedes conseguir gran cantidad de software en principio portable (i.e no ocupa instalarse) y entre sus filas milita mucho software free o open, yo lo estoy evaluando el sitio y hasta el momento me parece muy completo.

My Cow parade


http://www.mycowparade.net Full recomendado, este sitio conserva una de las más grandes colecciones de las vaquitas que se formaron parte de la muestra de arte, del cowparade, San José y que si mas no me equivoco, ahora se encuentran en las ruinas de Cartago.
Excelente recopilación y sin mas, mis sinceras felicitaciones al creador!

miércoles, noviembre 19, 2008

Algunas cosas acerca de Herencia, sobre escritura y métodos estaticos

A continuación vamos a realizar un pequeño estudio, acerca de dos cosas, la primera de ellas es probar que pasa cuando ponemos los keywords, final y static al mismo tiempo en una clase, la segunda es determinar el comportamiento de las clases cuando se sobre escribe un método estático.

1) Tomando en cuenta que una clase final no puede ser extendida y una clase abstract debe ser extendida, cuando intentamos hacer:

public final abstract class ImposibleAbstractClass {

public abstract void doSomething ();
}

El compilador nos muestra el siguiente error de compilación:

"The class ImposibleAbstractClass can be either abstract or final, not both"

Osea, no se puede hacer.

2) Que pasa cuando sobre cargamos un método estático:

Veamos el siguiente código:
public class A {

public static void a () {

System.out.println("A");
}

public void b () {

System.out.println("a");
}
}

public class B extends A {

public static void a () {

System.out.println("B");
}

@Override
public void b() {

System.out.println("b");
}

}

public class Main {

@SuppressWarnings("static-access")
public static void main(String[] args) {

A a = new A ();
A b = new B ();

a.a(); // funciona x tipo
b.a();

System.out.println("***********");

a.b(); // funciona x polimorfismo, osea por implementación.
b.b();

System.out.println("***********");

A.a(); // Llamado directo a la clase, no hay quite.
B.a();

}
}

Resultado:
A
A
***********
a
b
***********
A
B

Como pueden ver y a diferencia del comportamiento polimorfico, la implementación del método la otorga el tipo y no la implementación.
Si cambiamos;
A a = new A ();
A b = new B ();

Por

A a = new A ();
B b = new B ();

El resultado cambia a:
A
B

Por que el tipo de la variable "b" paso de A a B, y por esta razón utiliza esta sobrecarga.

lunes, noviembre 17, 2008

Test de eficiencia en concatenación de Java String.

El siguiente código resulta muy interesante, en el grado que nos permite experimentar con diferentes implementaciones de CharSequence, para concatenar caracteres (string con +, string utilizando el método concat, StringBuilder, StringBuffer y una biblioteca de terceros que implementa un nuevo objeto llamado Ropes, el cual asegura ser mas rápido y eficiente que el StringBuffer y el simple String (+ info: http://ahmadsoft.org/ropes/).

Los resultados a la vista son muy interesantes, el StringBuilder gana la lucha en eficiencia y eficacia. Y la razón del resultado recae en la estrategia de bufereo y que el objeto no sea sincronizado, muy cerca le sigue el StringBuffer el cual utiliza la misma estrategia de buffering, sin embargo es un objeto sincronizado, seguido por la biblioteca propietaria Ropes, la utilizaron del método String.concat() se encuentra de penúltima, la ultima y altamente no recomendable es la utilización del operador + para concatenar; esta operación no solo es lenta, también utiliza mucha memoria y hace que nuestra aplicación ocupe mas tiempo de proceso, practicamente mas de 250 veces mas lento en el manejo intensivo de concatenación que utilizar StringBuilder.

Aquí los resultados:

47 = StringBuilder
52 = StringBuffer
286 = Ropes
61079 = String.concat().
137514 = string = string1 + string2;
Este resultado se encuentra en milli segundos.



import java.util.Map;
import java.util.TreeMap;

import org.ahmadsoft.ropes.Rope;


public class ConcatenationStringExample {

public void concat() {

Map resultTimeMap = new TreeMap ();
Map resultMenMap = new TreeMap ();
final CharSequence s = "Hello classmate, this is the concatening example, !@#$%^&*()_+, @@@###@@@ 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111======================blauppee";
final int repeat = 6000;


long totalTime = 0;
long totalMem = 0;

long iniMem = Runtime.getRuntime().freeMemory();
long initTime = System.currentTimeMillis();

this.simpleConcatString(s, repeat);

totalTime = System.currentTimeMillis() - initTime;
totalMem = iniMem - Runtime.getRuntime().freeMemory();

System.out.println("Total time in millis: " + totalTime
+ ", total memory used: " + totalMem);

resultTimeMap.put(totalTime, "simpleConcatString");
resultMenMap.put(totalMem, "simpleConcatString");
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
/**/
}
// //////////////////////////////////////////////////////////////
iniMem = Runtime.getRuntime().freeMemory();
initTime = System.currentTimeMillis();

this.concatString(s, repeat);

totalTime = System.currentTimeMillis() - initTime;
totalMem = iniMem - Runtime.getRuntime().freeMemory();

System.out.println("Total time in millis: " + totalTime
+ ", total memory used: " + totalMem);

resultTimeMap.put(totalTime, "concatString");
resultMenMap.put(totalMem, "concatString");
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
/**/
}
// //////////////////////////////////////////////////////////////
iniMem = Runtime.getRuntime().freeMemory();
initTime = System.currentTimeMillis();

this.concatStringBuffer(s, repeat);

totalTime = System.currentTimeMillis() - initTime;
totalMem = iniMem - Runtime.getRuntime().freeMemory();

System.out.println("Total time in millis: " + totalTime
+ ", total memory used: " + totalMem);

resultTimeMap.put(totalTime, "concatStringBuffer");
resultMenMap.put(totalMem, "concatStringBuffer");
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
/**/
}
// //////////////////////////////////////////////////////////////
iniMem = Runtime.getRuntime().freeMemory();
initTime = System.currentTimeMillis();

this.concatStringBuilder(s, repeat);

totalTime = System.currentTimeMillis() - initTime;
totalMem = iniMem - Runtime.getRuntime().freeMemory();

System.out.println("Total time in millis: " + totalTime
+ ", total memory used: " + totalMem);

resultTimeMap.put(totalTime, "concatStringBuilder");
resultMenMap.put(totalMem, "concatStringBuilder");
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
/**/
}
// //////////////////////////////////////////////////////////////
iniMem = Runtime.getRuntime().freeMemory();
initTime = System.currentTimeMillis();

this.concatRopes(s, repeat);

totalTime = System.currentTimeMillis() - initTime;
totalMem = iniMem - Runtime.getRuntime().freeMemory();

System.out.println("Total time in millis: " + totalTime
+ ", total memory used: " + totalMem);

resultTimeMap.put(totalTime, "concatRopes");
resultMenMap.put(totalMem, "concatRopes");

System.out.println("***************-*******************");
System.out.println("time results with " + (repeat) + " repeat :" + resultTimeMap.toString().replaceAll(",","\n"));
System.out.println("Memory results with " + (repeat) + " repeat :" + resultMenMap.toString().replaceAll(",","\n"));

} // concat.

private void concatRopes(final CharSequence sequence, final int repeat) {

Rope string = null;

string = Rope.BUILDER.build(sequence);
for (int i = 0; i < Math.abs(repeat); ++i) {

string = string.append(sequence.toString());
}
System.out.println("concatRopes length: " + string.length());
} // concatRopes.


private void concatStringBuilder(final CharSequence sequence, final int repeat) {

StringBuilder string = null;

string = new StringBuilder(sequence);
for (int i = 0; i < Math.abs(repeat); ++i) {

string.append(sequence);
}
System.out.println("concatStringBuilder length: " + string.length());
} // concatStringBuilder.


private void concatStringBuffer(final CharSequence sequence, final int repeat) {

StringBuffer string = null;

string = new StringBuffer(sequence);
for (int i = 0; i < Math.abs(repeat); ++i) {

string.append(sequence);
}
System.out.println("concatStringBuffer length: " + string.length());
} // concatStringBuffer.


private void concatString(final CharSequence sequence, final int repeat) {

String string = null;

string = new String(sequence.toString());
for (int i = 0; i < Math.abs(repeat); ++i) {

string = string.concat(sequence.toString());
}

System.out.println("concatString length: " + string.length());
} // concatString.

private void simpleConcatString(final CharSequence sequence,
final int repeat) {

String string = null;

string = new String(sequence.toString());
for (int i = 0; i < Math.abs(repeat); ++i) {

string = string + sequence;
}

System.out.println("simpleConcatString length: " + string.length());
} // concatString.

public static void main(String[] args) {

ConcatenationStringExample example = new ConcatenationStringExample();
example.concat();
}
} // ConcatenationStringExample.

Comparación de cadenas en Java

El siguiente código nos muestra diferentes formas y métodos para realizar comparaciones de cadenas.
La primera comparación con el operador (==), se realiza simplemente a nivel de referencia de memoria. El método (equals) permite realizar una comparación carácter a carácter de dos strings. (equalsIgnoreCase) funciona igual que (equals) descartando las diferencias entre mayúsculas y minúsculas. (CompareTo) permite comparar dos cadenas, con la diferencias que si la clase es igual retorna 0, si la primera cadena es mayor retorna la diferencia (un numero positivo), si la cadena es menor retorna también la diferencia (un numero negativo).
Por ultimo se utilizan métodos para realizar comparaciones de pre y pos cadenas, obtener un índice, etc.

public void comparisonEqual () {

String s1 = "Hello Word";
String s2 = "Hello Word";
String s3 = s1;

// Equal examples...
System.out.println((s1 == s2)?s1 + " = " + s3: s1 + " != " + s3);
System.out.println((s1 == s3)?s1 + " = " + s3: s1 + " != " + s3);

s3 = "hello word";
System.out.println((s1.equals(s2))?s1 + " equals " + s2: s1 + " !equals " + s2);
System.out.println((s1.equals(s3))?s1 + " equals " + s3: s1 + " !equals " + s3);

System.out.println((s1.equalsIgnoreCase(s2))?s1 + " equalsIgnoreCase " + s2: s1 + " !equalsIgnoreCase " + s2);
System.out.println((s1.equalsIgnoreCase(s3))?s1 + " equalsIgnoreCase " + s3: s1 + " !equalsIgnoreCase " + s3);

System.out.println(this.customEqual(s1, s2)?s1 + " customEqual " + s2: s1 + " !customEqual " + s2);
System.out.println(this.customEqual(s1, s3)?s1 + " customEqual " + s3: s1 + " !customEqual " + s3);

s1 = s1.toLowerCase();
System.out.println(this.customEqual(s1, s3)?s1 + " customEqual " + s3: s1 + " !customEqual " + s3);

// comparison examples....
System.out.println(s1 + " compareTo " + s3 + ":" + s1.compareTo(s3));

s3 = s3.substring(2);
System.out.println(s1 + " compareTo " + s3 + ":" + s1.compareTo(s3));

System.out.println(s3 + " compareTo " + s1 + ":" + s3.compareTo(s1));

// comparison and finding examples...
System.out.println("s1.startsWith(\"hell\"): " + s1.startsWith("hell"));
System.out.println("s1.toUpperCase().startsWith(\"HELL\"): " + s1.toUpperCase().startsWith("HELL"));

System.out.println("s1.endsWith(\"ord\"): " + s1.endsWith("ord"));

System.out.println("s1.indexOf('o'): " + s1.indexOf('o'));
System.out.println("s1.indexOf('o', s1.indexOf('o')): " + s1.indexOf('o', s1.indexOf('o') + 1));

System.out.println("s1.lastIndexOf('o'): " + s1.lastIndexOf('o'));

System.out.println("s1.contains(\"o w\"): " + s1.contains("o w"));
}

public boolean customEqual (String s1, String s2) {

boolean isequal = s1.length() == s2.length();

if (isequal) {

for (int i = 0; i < s1.length(); i++) {

isequal &= (s1.charAt(i) == s2.charAt(i));
}
}

return isequal;
}

String en Java

Ahora nos centraremos en objetos CharSequence, esta interface es implementada por varios objetos, tales como; String, StringBuilder, StringBuffer, CharBuffer. Ahora nos centraremos en los primeros 3 objetos, pero tomando más importancia al objeto String.

String s = "Hello Word";

System.out.println("chartAt: " + s.charAt((s.length() - 1) / 2));
System.out.println("codePointAt: " + s.codePointAt((s.length() - 1) / 2));

System.out.println("isEmpty: " + s.isEmpty());
System.out.println("split: " + java.util.Arrays.toString(s.split("o")));
System.out.println("toCharArray: " + java.util.Arrays.toString(s.toCharArray()));
System.out.println("toCharArray: " + s.replace('o', 'a') );
System.out.println("toCharArray: " + s.replace("Hello", "Good bye") );

El método CharAt, nos permite obtener el carácter en una posición determinada.
El método codePointAt, nos proporciona el ascii correspondiente al carácter en la posición indicada.
El método isEmpty, solo indica si el objeto tiene un tamaño (length() == 0), igual a cero, si desea ver si un objeto es vacio o está lleno de blancos, aplique string.trim().length() == 0.
El método Split, crea un vector, resultado de dividir la cadena por algún token.
El método toCharArray, transforma la cadena en un vector de caracteres que componen la cadena.
El método replace, tiene diferentes sobrecargas para implementar un replace sobre el objeto, tome en cuenta que el string en realidad es un objeto de solo lectura, por lo tanto cualquier modificación al mismo, regularmente retorna la cadena resultante.

jueves, noviembre 13, 2008

Transformando fechas a diferentes zonas horarias (TimeZone)

Ya es sabido por todo programador Java, que uno de los puntos mas bajos, recae en el uso de las fechas, las mismas se encuentran super mal diseñadas y algunos objetos como el caso de Date, practicamente no son usables, pues toda su API esta deprecada (cosa que siento debería de dejar de ponerla deprecada, pues van por la versión 6 y aun la conservan). Recientemente me encontré con el siguiente problema; resulta que al poner un sistema en otro servidor, el cual aparentemente tiene una diferencia horaria configurada, obtenemos como seria de esperar resultados no esperados, cuando realizamos consultas con fechas a la base de datos. La primera solución que se nos ha ocurrido es implementar un convertidor de fechas a diferentes zonas horarias, a continuación coloco el método necesario para realizar la operación:


public static Date convertToTimeZoneDate(Date date, TimeZone timeZone) {

Date newTimeZoneDate = null;
Calendar foreignCalendar = null;
// Create a Calendar object with the local time zone
Calendar localCalendar = new GregorianCalendar();
localCalendar.setTime(date);

// Create an instance using foreign time zone and set it with the local
// UTC
strangerCalendar = new GregorianCalendar(timeZone);
strangerCalendar.set(Calendar.HOUR_OF_DAY, localCalendar
.get(Calendar.HOUR_OF_DAY));
strangerCalendar.set(Calendar.MINUTE, localCalendar
.get(Calendar.MINUTE));
strangerCalendar.set(Calendar.SECOND, localCalendar
.get(Calendar.SECOND));

// Create a Calendar object with the local time zone and set
// the UTC from foreign calendar
newTimeZoneDate = new Date(strangerCalendar.getTimeInMillis());

return newTimeZoneDate;
} // convertToTimeZone.

Este conveniente método, puede usarse de la siguiente forma:


String newTimeZoneId = "Chile/Continental";
Calendar calendar = new GregorianCalendar ();
Date date2 = calendar.getTime();
System.out.println(date2 + ":" + calendar.getTimeZone().getID());
System.out.println(convertToTimeZoneDate(date2, TimeZone
.getTimeZone(newTimeZoneId)) + ":" + newTimeZoneId);


Este código nos permite, obtener convertir nuestra fecha actual a la hora en chile. Para obtener la lista de las zonas horarias disponibles, puede ejecutar el siguiente código:


import java.io.PrintStream;
import java.util.Date;
import java.util.TimeZone;

public class TimeZoneAvailable {

/**
*
*/
public TimeZoneAvailable() {
}

public void execute() {

this.printTimeZones(System.out);
}

public void printTimeZones (PrintStream out) {

Date today = new Date();

// Get all time zone ids
String[] zoneIds = TimeZone.getAvailableIDs();

out.println("zoneIds.length = " + zoneIds.length);
// View every time zone
for (int i = 0; i < zoneIds.length; i++) {
// Get time zone by time zone id
TimeZone tz = TimeZone.getTimeZone(zoneIds[i]);

// Get the display name
String shortName = tz.getDisplayName(tz.inDaylightTime(today),
TimeZone.SHORT);
String longName = tz.getDisplayName(tz.inDaylightTime(today),
TimeZone.LONG);

// Get the number of hours from GMT
int rawOffset = tz.getRawOffset();
int hour = rawOffset / (60 * 60 * 1000);
int min = Math.abs(rawOffset / (60 * 1000)) % 60;

// Does the time zone have a daylight savings time period?
boolean hasDST = tz.useDaylightTime();

// Is the time zone currently in a daylight savings time?
boolean inDST = tz.inDaylightTime(today);

out.println(zoneIds[i] + ", " + shortName + ", " + longName + ", "
+ hour + ", " + min + ", hasDST: " + hasDST
+ ", inDST: " + inDST);
}
}

public static void main(String[] args) {

new TimeZoneAvailable().execute();
}
}







martes, noviembre 11, 2008

Un viaje a través de los Vectores en Java

import java.util.ArrayList;
import java.util.List;

public class Arrays {

public void example1() {

int i = 0;
// Diferentes formas de declarar un array.
Object[] objectArray = null;
String[] stringArray = new String[10];
int[] intArray = new int[] { i++, i++, i++, i++, i++, i++, i++, i++,
i++, i++ };
Character[] characterArray = { 'a', 'b', 'c' };
char[] charArray = new char[26];

for (int j = 0; j < stringArray.length; j++) {

stringArray[j] = String.valueOf(j);
}

List listString = java.util.Arrays.asList(stringArray);
System.out.println("listString = " + listString);

System.out
.println("java.util.Arrays.binarySearch(characterArray, 'c') = "
+ java.util.Arrays.binarySearch(characterArray, 'c'));

System.out
.println("java.util.Arrays.binarySearch(characterArray, 'd') = "
+ java.util.Arrays.binarySearch(characterArray, 'd'));

System.out
.println("java.util.Arrays.equals(characterArray, new char [] {'a','b','c'}); = "
+ java.util.Arrays.equals(characterArray,
new Character[] { 'a', 'b', 'c' }));

System.out
.println("java.util.Arrays.equals(characterArray, new char [] {'d','f','g'}); = "
+ java.util.Arrays.equals(characterArray,
new Character[] { 'd', 'f', 'g' }));

java.util.Arrays.fill(charArray, 'a');
System.out.println("charArray = "
+ java.util.Arrays.toString(charArray));

System.out.println("java.util.Arrays.hashCode(characterArray) = "
+ java.util.Arrays.hashCode(characterArray));

char[] orderArrayExample = new char[] { 'c', 'a', 'b', 'x', 'z', 'e',
'h' };
java.util.Arrays.sort(orderArrayExample);
System.out.println("orderArrayExample = "
+ java.util.Arrays.toString(orderArrayExample));

System.out.println("buildStringArray = "
+ java.util.Arrays.toString(buildStringArray("one", "two",
"three")));
} // example1.

public String[] buildStringArray(String... strings) {

List listString = new ArrayList();

for (String string : strings) {

listString.add(string);
}

return listString.toArray(new String[] {});
} // buildStringArray.

public static void main(String[] args) {

new Arrays().example1();
}
}

Las primeras líneas de código, encontramos diferentes maneras de inicializar un vector en Java; lo primero que debes notar, es que en Java los vectores representa un tipo de dato (Array) por eso se deben colocar los corchetes (se puede tanto al inicio como al final de la variable), puedes inicializarlo a null, colocarle una cantidad inicial (en donde todos los valores serán nulos o se almacenaran los valores por defecto en el caso de los datos primitivos), sin indicar el tamaño, pero proporcionando un conjunto de datos iníciales entre paréntesis (en este caso no siempre es necesario el uso del operador new).

A continuación podemos apreciar la forma de llenar un vector a través de una instrucción “for”, como crear un objeto List a partir de un Vector, como hacer una búsqueda binaria valiéndonos del objeto, java.util.Array, también el equals para comparar dos vectores, fill para llenar un vector con un idéntico valor, como obtener una representación en String de nuestro vector, como aplicar hashCode a cada elemento dentro del vector, como realizar el ordenamiento de un vector (tome en cuenta que en el caso de los tipos no primitivos, usted deberá asegurar que estos objetos implementan la comparación, a través de la interface Comparable o pasar como argumento un objeto Comparator).

Por último se muestra un método propio para crear un vector, la única observación es la notación parte de Java 5, para obtener “N” parámetros, si observa la implementación del método, el objeto recibido es enumerable, por lo que lo podemos utilizar a través de un “foreach”. En caso que desee utilizar esta funcionalidad en otro método, solo se puede recibir uno de ellos y tiene que ser declarado como el último argumento.

Creando un TLD dinamicamente con tobago apt plugin y Struts

Una de las tareas tediosas en JEE, es la de mantener nuestros TLD (definición de  librerías de Tag), cada vez que se cambia o agrega algo. Hace poco publique un post donde se explicaba como realizar taglibs utilizando el API de componentes de Struts, pues ahora se mostrara un plugin para Maven, mediante el cual podemos generar automáticamente un TLD, como observación interesante, cuando el TLD se almacena bajo el “META-INF”, no hay necesidad de agregarlo al “web.xml”, ni necesidad de tenerlo en bajo la estructura de directorios del WEB-INF.

Lo primero que debemos hacer, es agregar la carpeta “META-INF”, bajo main/resources, una nota al pie; Maven filtra cualquier directorio que no tenga ningún archivo, por lo tanto puedes agregar bajo “META-INF”, un archivo “README.txt”, con un mensaje como este (yo lo copie de Struts 2)

TLD file is generated inside META-INF after compilation.
If META-INF is empty, Maven will not copy it to the "target/classes" folder.
Please do not remove META-INF, or this file.

Esto permite que nuestra carpeta de “META-INF”, sea creada cuando se deploya el sobre la carpeta target, en caso que ya tengas un “META-INF” con al menos un archivo dentro, puedes omitir este paso.

El segundo paso es crear, la carpeta /src/site/resources/tags, en esta nuestro plugin almacena una serie de plantillas que utiliza para crear el TLD.

El siguiente trabajo es ir al pom.xml de Maven; en la sección de plugin e incluiremos el siguiente código:

                org.apache.myfaces.tobago
                maven-apt-plugin
                
                    target
                    false
                    true
                    true
                    true
                    org.apache.struts.annotations.taglib.apt.TLDAnnotationProcessorFactory
                    1.5
                    
                        **/*.java
                    
                
                
                    
                        compile
                        
                            execute
                        
                
                
            

Este plugin nos permite indicarle, los parámetros que deseamos utilizar para nuestro taglib, uri por ejemplo será el nombre de nuestro taglib, etc. El resultado cuando invoques a Maven compile, o algun objetivo que incluya esta fase del ciclo de vida, como packaged o install, seria algo como:

  2.2.3
  1.2
  my
  /my-tags
  "My Tags"
  

Puedes utilizar tanto los parámetros include o exclude al estilo de Ant, para agregar o limitar los paquetes o archivos a analizar.

Si te corres el nuevo pom.xml con tu Maven, te darás cuenta que el mismo crea tus taglib de HelloWord, que se había implementado en el articulo mencionado al inicio de este, sin embargo los atributos que incluye tu no los pusiste y además, en caso que agregues un atributo adicional, el taglib no será actualizado con este. Lo que pasa es que necesitas indicarle al Engine que crear el TLD, que tiene un atributo y deseas que el mismo se agregue al TLD, esto lo realizamos sencillo, anotando nuestro método set, con el siguiente annotation:

 @StrutsTagAttribute(description="Some attribute description", type="String", required=true)
Public void setNewAttribute () { …

Esto le indica, al Engine que este atributo debe ser agregado en nuestro TLD.


Como podrás notar, este proceso nos proporciona gran facilidad de mantenimiento y escalabilidad, pues el proceso de edición y creación de los taglib, se lo relegamos al ciclo de vida gestionado por Maven.

Algunos recursos de interés:

domingo, noviembre 09, 2008

Uso aplicado de la instrucción "For"


A continuación se presenta una pequeña aplicación, donde se utiliza la instrucción de control "For". Este ejemplo muestra como construir un Applet y como dibujar sobre ella (utilizando para ello la instrucción "For"), una seria de rombos, existen dos prototipos (métodos), el primer "paintRomboLine", resulta mas fácil de entender, pero necesita mas código para funcionar (4 instrucciones "for"), el segundo prototipo solo ocupa una instrucción "for", y realiza una serie de cálculos por cuadrantes.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;

import javax.swing.JApplet;

/**
 * Simple class to paint a rombo based in lines.
 * 
 * @author jsanca
 * 
 */
public class DrawRombo extends JApplet {

private static final long serialVersionUID = 7677516509658561962L;

public DrawRombo() throws HeadlessException {

super();
setSize(new Dimension(1200, 1200));
} // DrawCircularLine.

@Override
public void paint(Graphics g) {

int y = 180;
int x = 180;
int intensity = 4;

super.paint(g);
this.paintRomboLine(g);
this.paintRomboLine(g, x, y, intensity);

y = 270;
x = 90;
intensity = 2;
this.paintRomboLine(g, x, y, intensity);

y = 270;
x = 270;
intensity = 1;
this.paintRomboLine(g, x, y, intensity);

y = 360;
x = 180;
intensity = 8;
this.paintRomboLine(g, x, y, intensity);

y = 540;
x = 180;
intensity = 16;
this.paintRomboLine(g, x, y, intensity);

y = 450;
x = 90;
intensity = 90;
this.paintRomboLine(g, x, y, intensity);

y = 450;
x = 270;
intensity = 45;
this.paintRomboLine(g, x, y, intensity);
} // paint.

private void paintRomboLine(Graphics graphics) {

int x1 = 90;
int y1 = 90;
int x2 = x1;
int y2 = y1 - 90;

for (int i = 0; i <= 90; ++i) {

graphics.drawLine(x1, y1, x2++, y2++);
}

for (int i = 0; i <= 90; ++i) {

graphics.drawLine(x1, y1, x2--, y2++);
}

for (int i = 0; i <= 90; ++i) {

graphics.drawLine(x1, y1, x2--, y2--);
}

for (int i = 0; i <= 90; ++i) {

graphics.drawLine(x1, y1, x2++, y2--);
}

} // paintRomboLine.

private void paintRomboLine(Graphics graphics, final int x, final int y,
final int intensity) {

int x1 = Math.abs(x); // 180; // 90;
int y1 = Math.abs(y); // 180; // 90;
int x2 = x1;
int y2 = y1 - 90;
int cuadrante = 0;
int div = Math.abs(intensity);
div = (div == 0) ? 1 : div;
int iteration = 360 / div;

for (int i = 0; i <= iteration; ++i) {

if (i % (iteration / 4) == 0) {

cuadrante += 1;
}

x2 += (1 * intensity)
* ((cuadrante == 2 || cuadrante == 3) ? -1 : 1);
y2 += (1 * intensity)
* ((cuadrante == 3 || cuadrante == 4) ? -1 : 1);

graphics.drawLine(x1, y1, x2, y2);
}
} // paintCircularLine.

} // E:O:F:DrawCircularLine.


sábado, noviembre 08, 2008

Al fin MTV reconoce el potencial de la Internet

Después de mucha lucha y denuncias públicas y demás pleitos para llamar la atención, la cadena mundial de música por televisión mas grande el mundo MTV, abren toda su biblioteca (bueno casi toda, el material en ingles por el momento), al publico. Aseguran tener conciertos, espectáculos acústicos, más todos sus vídeos y a diferencia de YouTube (que es mantenida por una comunidad en buena parte), esta es soportada por MTV, lo que le proporciona idéntica calidad a cada uno de sus temas (vídeos), el sitio en donde han publicado el contenido le llaman MTV Music, y yo debo reconocer que estoy como chiquito con juguete nuevo, jejeje.
El sitio ofrece una gran cantidad de música, como señale anteriormente y además realiza sugerencias acerca de música o vídeos relacionados, en las búsquedas, te de la oportunidad de ir a un perfil del artista o directamente a los vídeos. Buena noticia y supongo que a MTV le paso como dicta el viejo adajio, "si no puedes vencerlos, uneteles".

Para los que les encanta Tori Amos, les dejo el link a una de sus mas melancólicas canciones, China, disfruten del tema, tanto como yo!

miércoles, noviembre 05, 2008

Creando e integrando "custom taglibs" con Struts 2.x, Spring y FreeMarker




Creando un taglib, extendido de los componentes de Struts.


Recientemente surgió la necesidad de crear un “taglib”, para un proyecto en el cual estoy trabajando, hasta ahí todo bien. El problema inicia cuando deseamos reutilizar los componentes de Struts (utilizamos la versión 2.x). Después de investigar un poco, nos encontramos con el “tag” (“<s:component />”), este permite pasarle un nombre de plantilla (de Velocity o FreeMaker) y renderizar el resultado en nuestro Html, por ejemplo, si tenemos:


<component template="/my/custom/component.vm”>

    <s:param name="key1" value="value1"/>

    <s:param name="key2" value="value2"/>

</s:component>


Esto invocará una plantilla de Velocity e introduce al contexto de Velocity, un Mapa llamado “parameters”, del cual podemos obtener los parámetros que anteriormente insertamos en el JSP.

Más o menos, algo así:


${parameters.key1}


Este enfoque esta bastante bien, sin embargo tiene algunos problemas; la implementación queda totalmente expuesta a los WebDev. En caso que deseemos utilizar alguna clase nuestra o solicitar a Spring algún componente del contexto, la tarea se dificulta.


La solución mas adecuada sería extender este funcionamiento, para encapsular y reutilizar la funcionalidad del componente de Struts y proporcionar componentes fáciles de utilizar a los WebDev.


Investigando un poco, tuvimos la sensación que la documentación necesaria para implementar este tipo de extensiones al Framework, al momento no se encuentra muy documentado (por no decir que no existe) o nadie ha necesitado hacerlo. Sin más opción, ni guía, nos consumimos en el código fuente de Struts 2 y del estudio de ciertas partes del código, encontramos una solución, la misma se detalla a continuación:


Nuestra prueba de concepto consiste en crear un “taglib”, llamado HelloWord, el cual recibirá mediante un atributo llamado “name”, el nombre de la persona a saludar.


Lo primero que tenemos que hacer, es crear un componente el cual implemente la interfase “org.apache.struts2.views.TagLibrary”, esta interfase permite a Struts conocer los componentes y “taglibs” que deseamos utilizar, así pues creamos la siguiente clase:


public class MyTagLibrary implements TagLibrary {

       @Override

       public Object getFreemarkerModels(ValueStack stack, HttpServletRequest req,

            HttpServletResponse res) {

             

              return new MyModels(stack, req, res);

       } // getFreemarkerModels.

       @Override

       public List<Class> getVelocityDirectiveClasses() {

              return null;

       } // getVelocityDirectiveClasses.

}


Como podrá ver, esta clase tiene dos métodos, mediante los cuales le damos a conocer a Struts tanto, los componentes de Velocity (ninguno en nuestro caso) y los componentes de FreeMaker (para este caso se utiliza un Objeto, se trata de MyModels ya lo vemos en mas detalle).


Adicionalmente, este objeto debe ser agregado en nuestro archivo de configuración:


<struts>

<bean type="org.apache.struts2.views.TagLibrary" name="my" class="com.mypackage.web.views.MyTagLibrary" />


Esto permite al Struts, conocer que existe una fábrica para los componentes “taglib”, importante colocarle el atributo (type), pues mediante este, Struts se percata de que existe y debe ser procesado como una fabrica de TagLibrary. Importante saber, que el valor de “name”, en nuestro caso “my” es algo así como el nombre del “namespace” del taglib, ósea que al final debe utilizarse el “taglib”, mas o menos así: <my:nombreTagLib.


El siguiente paso, es crear nuestra fábrica de modelos; en el caso que desees utilizar Freemaker, debes crear un objeto el cual supongo que Struts analizará por reflexión, pues no implementa nada, simplemente utiliza la nomenclatura que a continuación te muestro:


public class MyModels {


    protected ValueStack stack;

    protected HttpServletRequest req;

    protected HttpServletResponse res;    

    protected HelloWordModel helloWord;

   

       public MyModels (ValueStack stack, HttpServletRequest req,

                     HttpServletResponse res) {

              super();

              this.stack = stack;

              this.req = req;

              this.res = res;

       }


       public HelloWordModel getHelloWord() {

             

              if (null == this.helloWord) {

                    

                      this.helloWord = new HelloWordModel (this.stack, this.req, this.res);

              }

             

              return helloWord;

       }   

}


Pronto explicaremos en detalle de que se trata este “HelloWordModel”, ahora lo importante es saber, que para que Struts descubra nuestro “taglib” ocupa un objeto “TagModel”, observe que la convension es:


Public XXXModel getXXX(), donde XXX es el nombre del componente, en el ejemplo anterior “HelloWord”, usted puede colocar los componentes que ocupe guardar bajo este “namespace”.


Por cada “TagLib” que ocupemos debemos crear al menos 3 objetos, el primero será el modelo, este le sirve al Struts para describir tanto el TagLib, como el “bean” que será introducido en el contexto del motor de plantillas.

Así pues, veamos el modelo:


public class HelloWordModel extends TagModel {

      

       public HelloWordModel(ValueStack stack, HttpServletRequest req,

                     HttpServletResponse res) {

              super(stack, req, res);

       }

      

       @Override

       protected Component getBean() {

             

              return new HelloWord(this.stack, this.req, this.res);

       }

}


Esta clase extiende de “TagModel”, clase la cual, según el contrato de la misma nos exige devolver un “Component”, al invocar al método “getBean”, Aquí vamos a devolver el objeto que necesitamos sea leído por el motor de plantillas, podemos ver analógicamente este objeto “Model”, como una fabrica “Home” en el contexto de los E.J.B.


A continuación creamos nuestro, Java Bean, HelloWord:


@StrutsTag(name="helloWord", tldTagClass="com.mypackage.web.ui.HelloWordTag", description="Hello word example!")

public class HelloWord extends GenericUIBean {


       final public static String TEMPLATE = "helloword";

      

       private String name = null;


       @Override

       protected String getDefaultTemplate() {

      

              return TEMPLATE;

       }

      

       public String getName() {

              return name;

       }


       public void setName(String name) {

              this.name = name;

       }


      

       public HelloWord(ValueStack stack, HttpServletRequest request,

                     HttpServletResponse response) {

              super(stack, request, response);

                     }


}


Puntos importantes de ver; primero nuestra clase extiende de “GenericUIBean”, existen otras clases en la jerarquía, las cuales podemos utilizar como clase base, algunas proporcionan menos o mas funcionalidad, al parecer. El segundo punto a tomar en cuenta, es sobre escribir el método “getDefaultTemplate”, este método permite indicarle al “Engine” de FreeMaker, al menos estilo del patrón template, que la plantilla de FreeMaker, que deseamos utilizar es tal (ojo que la extensión se omite, solo se coloca el nombre). Por ultimo, cualquier atributo al estilo Java Bean (i.e: atributos con sus respectivos set’s y get’s), podrán ser accedidos desde la plantilla de FreeMaker. El constructor es necesario, así como la invocación al súper. Lo ultimo que debemos prestar atención, es la inclusión de una anotación, la cual relaciona nuestro Java Bean, con un “TagLib”, supongo que el “Engine” de FreeMaker toma nuestro objeto “model”, de ellos el JavaBean y de las anotaciones de estos, el taglib asociado.


Por ultimo implementaremos nuestro componente de vista, o lo que es lo mismo nuestro “taglib” propiamente, el mismo debe extender de la clase “ComponentTag”, la cual tiene el soporte necesario para renderizar la plantilla de FreeMaker, con el componente incluido. A continuación el código:


public class HelloWordTag extends ComponentTag {


       private String name = null;


       public String getName() {

              return name;

       }


       public void setName(String name) {

              this.name = name;

       }


       /**

        *

        */

       public HelloWordTag() {


              super();

       }


       @Override

       public Component getBean(ValueStack stack, HttpServletRequest req,

                     HttpServletResponse res) {


             

              return new HelloWord(stack, req, res);

       }


       @Override

       protected void populateParams() {


              HelloWord helloWord = null;

              super.populateParams();

              helloWord = HelloWord.class.cast(this.getComponent());

              helloWord.setName((null != this.getName()) ? this.getName() : "Fulano de tal");

       }


}


 


Note que la implementación del método; “getBean” al funciona al estilo del patrón plantilla y nos permite obtener el Java Bean que deseamos. También tenemos la sobre escritura del método populateParams, el cual nos permite setear parámetros en el componente, este método para los que conocen la interfase “InitializeBean” de Spring, es análogo al método “afterSetProperties”. Note que este Java Bean, tiene propiedades “bean”, las cuales deben ser expuestas mediante un “tld”.


Como lo indicamos en nuestro Java Bean, HelloWord, necesitamos crear nuestra plantilla de FreeMaker y situarla bajo el paquete Java: “template.simple”, el cual por supuesto debe estar en nuestro “classpath”. A continuación nuestro código para helloword.ftl:


<#assign helloword = tag/>


<p>

   Hello ${helloword.name}

</p>


Majestuoso no es cierto, nuestro bean es introducido con el nombre de “tag”, lo asignamos a “helloword” y solicitamos el nombre para saludar.


 


Una vez codificadas las clases y editados los archivos de configuración y FreeMaker, necesitamos integrar nuestro “Taglib”, con nuestro contexto Web, para ello realizamos los pasos de siempre; creamos un “TLD” con la descripción del “HelloWordTag” e incluimos este “TLD” en nuestro Web.xml.


A continuación el código del my-tags.tld:


<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

<taglib>

  <tlib-version>2.2.3</tlib-version>

  <jsp-version>1.2</jsp-version>

  <short-name>my</short-name>

  <uri>/my-tags</uri>

  <display-name>"My Tags"</display-name>

  <description><![CDATA["My Specific Tag."]]></description>

  <tag>

    <name>helloWord</name>

    <tag-class>com.mypackage.web.ui.HelloWordTag</tag-class>

    <body-content>JSP</body-content>

    <description><![CDATA[Hello word]]></description>

    <attribute>

      <name>name</name>

      <required>false</required>

      <rtexprvalue>false</rtexprvalue>

      <description><![CDATA[Name of the action to be executed (without the extension suffix eg. .action)]]></description>

    </attribute>   

  </tag>

 </taglib>


 


Ahora el código necesario para el web.xml:


<jsp-config>

   

      <taglib id="MyTLD">

         <taglib-uri>/my-tags</taglib-uri>

         <taglib-location>/WEB-INF/my-tags.tld</taglib-location>        

      </taglib>

    </jsp-config>


Por ultimo para utilizar nuestro “taglib”, declaramos el mismo en nuestro JSP y simplemente lo utilizamos:


<%@ taglib prefix="my" uri="/my-tags"%>


<my:helloWord name="Jsanca"></my:helloWord>


// <p>Hello Jsanca</p>


<my:helloWord ></my:helloWord>


// <p>Hello Fulano de tal</p>


Hasta aquí ya tenemos nuestro “taglib”, totalmente integrado con Struts y FreeMaker. En la mayoría de los casos y particularmente si utilizamos Spring, será muy probable que surja la necesidad de utilizar alguna clase declarada en nuestro contexto de Spring, a continuación el código que utilice para realizar la tarea:


HelloWordModel.java:


@Override

       protected Component getBean() {

              ApplicationContext applicationContext = WebApplicationContextUtils

                           .getWebApplicationContext(req.getSession().getServletContext());


              SaludadorService saludador = SaludadorService.class.cast(applicationContext

                           .getBean("saludador"));


              return new HelloWord(this.stack, this.req, this.res, saludador);

       }


HelloWord.java:


@StrutsTag(name="helloWord", tldTagClass="com.mypackage.web.ui.HelloWordTag", description="Hello word example!")

public class HelloWord extends GenericUIBean {


       final public static String TEMPLATE = "helloword";

      

       private String name = null;

      

       private SaludadorService saludador = null;

      


       @Override

       protected String getDefaultTemplate() {

      

              return TEMPLATE;

       }

      

       public String getName() {

              return this. saludador.buildSaludo(this.name);

       }


       public void setName(String name) {

              this.name = name;

       }


       /**

        * @param stack

        * @param request

        * @param response

        */

       public HelloWord(ValueStack stack, HttpServletRequest request,

                     HttpServletResponse response, SaludadorService saludador) {

              super(stack, request, response);

              this. saludador = saludador;

       }


}


HelloWordTag.java:


@Override

       public Component getBean(ValueStack stack, HttpServletRequest req,

                     HttpServletResponse res) {


              ApplicationContext applicationContext = WebApplicationContextUtils

                           .getWebApplicationContext(req.getSession().getServletContext());


              SaludadorService saludador = SaludadorService.class.cast(applicationContext

                           .getBean("saludador"));


              return new HelloWord(this.stack, this.req, this.res, saludador);


       }


 


Aquí el truco recae en utilizar la clase “WebApplicationContextUtils” y tener el acceso al objeto “Request”, pues como supondran la instancia del ApplicationContext de Spring, se encuentra almacenado en el ‘scope’ del ServletContext y mediante este método, podemos obtenerlo.


Espero les haya sido útil!