Wednesday, March 28, 2012
Move to Wordpress
Saturday, January 21, 2012
Using the Linaro Toolchain on Fedora
They don't provide RPMs of their tools so you have to either compile it from source or use Michael Hope LSB compatible prebuilt binaries.
For anyone insterested here is a mini-how:
$ yum install redhat-lsb.i686 $ wget -c http://people.linaro.org/~michaelh/incoming/binaries/gcc-linaro-arm-linux-gnueabi-2012.01-20120112+bzr2334~linux.tar.bz2 $ tar -xvf gcc-linaro-arm-linux-gnueabi-2012.01-20120112+bzr2334~linux.tar.bz2 $ mv gcc-linaro-arm-linux-gnueabi-2012.01-20120112+bzr2334~linux /opt/gcc-linaro $ echo "export PATH=\$PATH:/opt/gcc-linaro/bin" > /etc/profile.d/gcc-linaro.sh
Saturday, October 8, 2011
What is the best way to learn Linux kernel development?
The answer finally was longer than I thought so I decide that it was worth a post. I don't know if this is the best approach to learn Linux kernel development and get involved, but is the one I recommend nowadays.
I for example didn't follow these steps, I got involved first watching Greg KH's Write and Submit your first Linux kernel Patch excellent video. After that I realized that anyone (even me) could contribute to the Linux kernel so I cloned the linux-next integration tree, compiled and started sending trivial one-liners patches.
But, after getting a job as a Linux Kernel Engineer and being contributing to the kernel for some time now I realized that there is a better and more fun way to get involved. Obviously device drivers is the best way to get involved for two reasons.
First, unless you are a PhD student doing research on operating systems. It is very unlikely that you will came with a brilliant idea an start hacking the Linux kernel virtual memory or block device subsystem. The Linux kernel has 20 years of development and its core is very, very complex. Second, it is more probable that your first job as a Linux kernel developer will be to write device drivers.
But, whatever is the way you chose to get involved, there is a step you can't skip and is to learn the theory behind operating systems in general and the Linux kernel in particular. So if you don't know about operating systems, I recommend you to read Willam Stalling's OS book. This book has a more hardware oriented approach unlike other OS books that focus more on the algorithms and data structures used in operating systems than explaining with examples how things work in the real world.
After having a high level overview of operating systems, you have to learn about Linux kernel development. Robert Love's Linux Kernel Development book is for me the best one on the subject. You can learn not only about Linux kernel development, but also the motivations behind the technical decisions that lead to the design.
Then you have to learn about device drivers development on Linux, two books that are very good are Linux Device Drivers and Essential Linux Device Drivers. This two books are complementary. The former teaches how to write virtual device drivers for memory based devices, so you can try the examples without the need of special hardware. While the latter shows you how device drives for real devices are actually written. I maintain an up-to-date repository with all LDD3 examples so you can compile and test on recent kernels.
Once you have the theory you can begin with the practice by writing real device drivers. You need a hardware that still is not supported on Linux. The good news is that you probably already have on of this devices.
With the popularity of the Android platform, is very likely that you own an Android device. Even when Android is a Linux-based operating system, Google by a design decision forked the Linux kernel and added some APIs that don't exist on the Linux kernel. These APIs are used by device drivers and for that reason, a developer has to choose whether to write a device driver for Android or Linux.
So, porting Android device drivers to Linux is an excellent opportunity to learn device driver development skills, the Linux kernel development process and how to work with the Linux community while doing something useful.
A final comment, when asking questions to kernel developers on public mailing lists, remember to do your homework and researched first. They tend to be very polite and collaborative with people that show signs that they tried to understand the problem first before to ask, but can be a little grumpy with people that ask first before even tried to understand the problem.
Also, don't be afraid to contact the developers that wrote the Android version device driver. They usually are working for the company that build the hardware of were contracted by them. Usually both the company and the original developer also want the driver to be merged on the Linux kernel but they don't have neither the time nor the resources to do it.
So, if you offer them to help and your time to modify the driver to be in an merge-able state, they will be more than happy to help you finish the task. This is important because you probably will need the hardware datasheet or at least information about the people that know well the hardware.
Happy hacking!
Saturday, September 3, 2011
Building your own Nook Color Android kernel
So to work in a driver first you need to compile a Linux (or Android) kernel. Since I don't have a fully functional Linux kernel for the Nook Color, I'm developing against an Android kernel.
I want to document how to build your own Android kernel for two reasons. First someone could find it useful. Second, I wanted to document the process for myself. I context switch more than I would like and when I comeback to something I didn't do in a few days, I have to remember what are the exact commands to build the uImage, what is the defconfig file I use to build each kernel, etc. This happens even more with my hobbyists projects since I don't work with them on a daily basis.
So these are the steps to build a custom Android kernel for your Nook Color:
1- Installing CyangenMod (CM7) on an SD card:
First you have to decide if you want to install your kernel on your boot partition of your nand memory or using an external SD card. I prefer to only install stable software on my nand so I did an CM7 installation on an SD card and used that for development.
To install a CM7 on your SD card first download and gunzip the generic sd card image.
$ wget http://nook.handhelds.ru/sdimage/generic-sdcard-v1.3.img.gz
$ gunzip generic-sdcard-v1.3.img.gz
Then insert your SD card and copy the image to your SD card:
$ dd if=generic-sdcard-v1.3.img of=/dev/sdX bs=1024
Where X is the block device name for your SD card. To know which block device is associated with your SD card, insert your card and look the kernel log messages with dmesg for example.
After done with writing eject and insert again your SD card on your computer. Download a nightly build of CM7 for the Nook from http://download.cyanogenmod.com/?device=encore I'm using -153 but I guess that a newer or older should work either.
$ wget http://download.cyanogenmod.com/get/cm_encore_full-153.zip
One the file has been downloaded, copy it to the SD card. There should be only one partition on the SD.
$ mount /dev/sdX1 /media/boot
$ cp cm_encore_full-153 /media/boot
That's all, now unmount the SD card, insert it on the Nook and power off. The generic image will find and update file and automatically start CM7 installation. The process will re-partition your SD card and copy all the necessary files in each of them (x-loader MLO, uBoot u-boot.bin, kernel image and ramdisk in the boot partition, binaries and libraries in the rootfs partition, etc).
Once the installation is complete the Nook will power off and you have a fully functional CM7 installation on your SD card. The Nook Color has boot sequence when the SD card has higher precedence than the nand memory. If the SD card is inserted, the Nook will attempt to boot from there. So with the SD inserted, just turn on again the Nook an CM7 will boot from there.
That is, you now have a system to test your newer kernel.
2- Instal a ARM cross-compiling tool-chain
Since the Nook has an ARM processor and it is unlikely that your host machine is ARM base, you will need to install an ARM cross-compiling tool-chain to compile ARM Android images.
You can install different cross tool-chains both from source code and using pre-compiled packages for your host machine distribution. For example to install Linaro's GCC cross tool-chain you can use the following command on Debian and Debian-based distros (such as Ubuntu):
$ apt-get install gcc-arm-linux-gnueabi
3- Obtaining and compiling an Android kernel
Now you need CM7 Android kernel, this can be found in Dalingrin github repository.
$ git clone https://github.com/dalingrin/nook_kernel.git
Now you have to checkout a local branch for your work:
$ cd nook_kernel
$ git checkout -b devel origin/encore-32
Now you have a local branch devel to do your kernel development.
Do all the modifications you wish to the Android kernel and to compile your kernel first generate a .config file from the Nook Color defconfig file:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- omap3621_evt1a_defconfig
This will generate a .config file that contains all the symbols needed to compile Nook Color's board file and needed drivers. You can customize the build with:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
Once your kernel compilation is customized you can generate the kernel image with the following command:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage
Once it finish compiling, the uImage is located in arch/arm/boot/uImage.
The last step is to copy the uImage on the SD card. I prefer to mount the SD boot partition in the Nook Color using ssh or adb commands and copy the uImage using scp, but this setup will be explained in other article. Another option is to remove the SD card from the Nook, insert on your host machine, mounting the boot partition and copy the image:
$ mount /dev/sdX1 /media/boot
$ cp arch/arm/boot/uImage /media/boot
That is, now you can insert the SD card on your Nook Color and boot your customized Android kernel.
Happy Hacking!!
Friday, September 2, 2011
The power of open source
Besides using with Android I wanted to install Linux on it, but there isn't a fully functional Linux kernel for the Nook. So I contacted Oleg Drokin (a.k.a verygreen) and William Marone (a.k.a wmarone) that were working in porting Nook Color's Android drivers to Linux.
I pick the task to work on the Cypress TrueTouch (tm) touchscreen driver for upstream inclusion. I knew that Kevin McNeely from Cypress submitted a patch-set for a newer and better designed driver for the TrueTouch family. I contacted Kevin asking if I could take that patch-set as a starting point for the driver and what modifications were needed for the driver to be accepted.
Kevin kindly told me that a requirement was to modify the driver to use a different multi-touch protocol type from the one the driver had. So I modified the driver to use the newer multi-touch protocol type B. Kevin also gave me guidance, advice and code when I didn't understand the driver internals.
I posted a patch-set which was reviewed and a few issues were found. Again Kevin point me out what modifications are necessaries to fix these issues.
So that is what I'm working on in my free time. I'll keep modifying the driver and resubmitting the code until the patch is merged or Kevin and the folks from linux-input get tired of me.
This post is now longer than I would like, but I wanted to tell the full story to show the power of open source. I own a hardware that doesn't meet all my needs, I'm able to hack the device, modify it at my will and find help both from hobbyists and companies like Cypress and its engineers.
I think this is the best moment in history to be an engineer, 20 years ago one could only dream of having a modern operating system such as Linux or Android with its complete source code to read, understand and modify.
I know I want to be a FOSS hacker all my life. I don't think there could be a better way to build high quality software such as Linux.
Friday, July 22, 2011
10 years anniversary with computers
I have worked in many sectors doing different things. I have administered Linux servers, developed ERP systems for wholesale companies, design and developed enterprise mobile applications and location based services for a telco and even build a data-warehouse and a GIS for a distribution company.
Also, I've worked in Academia as a researcher, developing a performance analysis and estimation tool for parallel applications running in Linux clusters and published papers in international conferences.
I also contributed to my favorite open source project, the Linux kernel with 65+ patches pushed to mainline.
But the best of all is that I have finally realized what I want to do, I think I've found my path. I realized that I want to become a full-time FOSS hacker. My experience contributing to open source and working both in the industry and the academia, has showed me that it is near impossible to build proprietary (or academic) systems with the same quality of their open source counterparts.
As Eric Raymond said, "With many eyes, all bugs become shallow". But not only the eyes but also the passion that open source developers put to their work and the high level of scrutiny to the code you post.
Also I see open source as a vehicle to do research, as Dirk Hohndel of Intel said, "open source is the shortest path to innovation".
Also, the possibility that your work will be used by millions of people really inspire me. The good news is that because of my previous work with the Linux kernel, a company offered me a job to work full time as an Linux embedded engineer. That means I will be doing not only Linux kernel development but also Linux user space development and even boot-loader development!
I had to make a huge decision. Today I quit as a researcher at the Universitat Autònoma de Barcelona and give up my scholarship for PhD studies. I had the pleasure to work with very smart people while doing research. I'd like to thank my advisors, Dr Emilio Luque and Dr. Dolores Rexachs and fellows at the Computer Architecture and Operating Systems department at UAB.
But I think my decision is correct given the path I choose.
I will work hard and do my best to achieve all my goals in this new adventure. As Linus Torvalds said "Its no the great ideas that bring innovation, its sweat and hard work"
So from now on expect me to post more about Linux kernel development, embedded systems, C programming and things like that!
Monday, July 4, 2011
Emacs configuration for Linux kernel development
In this blog entry I will show you how to make the best of Emacs for Linux kernel development. We will see how to use from Emacs the cscope and tags symbol databases and to set the code indentation according to the Linux kernel coding style.
The first problem I had when starting doing kernel development (and in any medium size project that I was involved BTW) was browsing the code. The first attempt and a method I still use for find complicate expressions is to use the commands grep, frep and the grep git option (git grep). Also you can use the Linux Cross Reference (LXR).
Another approach is to use tools that were created to make it easy to browse source code. Two very used utilities are cscope and ctags. They both create a symbol database known as the index. This index have all global symbols, that in the case of C programs, this will be global and member functions, structures, enums, typedefs and #defines.
etags is a custom flavor of ctags that generates a database that can be used by Emacs.
The tools can be used both to create the index and also to navigate the symbols in the index, for example to find all the places in the code that a symbol is declared or used.
To manually create the index for cscope, first you have to list all the files that have symbols that you want to add to the index, you can do this using the find or whatever command line utility is best for you:
$ find . -name "*.c" -o -name "*.h" > cscope.files
then to build the database:
$ cscope -qkRv
and finally to browse the database:
$ cscope -d
A similar procedure is needed to build the database for etags:
$ etags `find . -name "*.c" -o -name "*.h"`
Create cscope and etags symbol databases for the Linux kernel
Creating the databases for both cscope and etags in the kernel source directory is straightforward since the kernel main Makefile has custom targets for doing this.
So, just go to the directory where the kernel source code is:
$ cd /path/to/linux/source/code
and to create the cscope database execute:
$ make cscope
and to create the etags database
$ make TAGS
Use cscope and etags from Emacs
Once the databases are created, to use it from Emacs just open a source file that is inside the kernel source directory (whose symbols are already in the databases).
To use cscope, you have to add this line to your ~/.emacs config file
(require 'xcscope)
Note: Remember has to special keys that can be used to create key sequences. These keys are the Control and Meta key. When specifying key sequences these key are usually refer as Ctrl and Meta or C and M. These can be confusing for a new Emacs user.
So the key sequences:
Ctrl+c s s
C-c s s
are the same, and so are:
Meta+x
M-x
The Control and Meta keys are usually mapped to the Control and Alt keys, but this is not necessary true and in fact most people remap the Control key to the Caps Lock keyboard key.
Then to navigate trough the symbols just put your cursor over a symbol and use one of these commands:
C-c s s Find symbol.
C-c s d Find global definition.
C-c s g Find global definition (alternate binding).
C-c s G Find global definition without prompting.
C-c s c Find functions calling a function.
C-c s C Find called functions (list functions called from a function).
C-c s t Find text string.
C-c s e Find egrep pattern.
C-c s f Find a file.
C-c s i Find files #including a file.
For a complete list of commands refer to the file: xcscope.el.
To use the etags database, first you have to tell emacs where the symbol database is, for example:
M-x visit-tag-table /path/to/linux/source/code/TAGS
to navigate, go to a function an do:
M-.
to go back
M-*
Configure Emacs indentation according to kernel coding style
The Linux kernel coding style is very strict. This ensures that anyone can modify the source code and it will always look consistent. To configure Emacs so its standard indentation uses the kernel coding style, add this line to your ~/.emacs config file:
(setq c-default-style "linux")
Also I have a few tweaks that maybe you find helpful, I list here a portion of my .emacs configuration relevant to development (since I have other uses for Emacs such as LaTex editing):
; Get rid of the startup message
(setq inhibit-startup-message t)
; Show file full path in title bar
(setq-default frame-title-format
(list '((buffer-file-name " %f"
(dired-directory
dired-directory
(revert-buffer-function " %b"
("%b - Dir: " default-directory)))))))
; Shows parenthesis
(show-paren-mode 1)
; Shows column number
(column-number-mode 1)
; Change default colors
(set-background-color "grey14")
(set-foreground-color "white")
(set-cursor-color "white")
; No toolbar
(progn
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
; (menu-bar-mode -1)
(scroll-bar-mode -1)
)
Sunday, April 17, 2011
Linux checkpoint restart mechanisms
tools that use process checkpoint/restart (CR). Basically the people here have found
three CR mechanism that actually works:
1- Berkeley lab's checkpoint/restart (BLCR)
Pros:
- Probably the most robust framework to CR in Linux. Is a hybrid
kernel-space/user-space implementation.
- You can compile OpenMPI message passing library to checkpoint distributed applications using BLCR. This is very convenient in HPC.
Cons:
- It looks that they are slowing down its development. The last
official release is 0.82 (June 16, 2009) and support kernel 2.6.30
(pretty old). To compile with newer kernels there are some patches
flowing in the development mailing list but I think only to give
support until 2.6.34 I think.
- You need root permissions to insert the blcr kernel module. One of
our tools used BLCR and we couldn't run in many clusters because the
sysadmins were skeptical about inserting a kernel module with a few
random patches published in a mailing list.
2- DMTCP: Distributed MultiThreaded CheckPointing
Pros:
- A completely user-space solution. You don't need to bother the
sysadmins to install kernel modules.
- Can checkpoint distributed computation (we already tried with
OpenMPI and it also checkpoints the orte daemon).
- There is current development to add DMTCP to OpenMPI for parallel applications checkpointing as a alternative to BLCR.
Cons:
- Since it is implemented in user-space it has a lot of workarounds to
maintain process state in userspace.
- Duplicates kernel-space process information.
- Only works with socket-based communications (it doesn't work with
proprietary infiniband protocols for example).
3- Linux-cr checkpoint/restart mechanism
Pros:
- The checkpoint/restart mechanism is implemented in the kernel as
syscalls and some user-space tools.
- Their intention is to push the mechanism upstream for kernel inclusion.
- Since their implementation is kernel based it is very robust.
Cons:
- The patch-set still didn't make for kernel inclusion. And the the
whole subject is complicated . Not all kernel developers agree that
implement CR in the kernel is a good idea.
- You need a custom kernel that has linux-cr support.
So which CR mechanism you choose will depend on many factors (if you have
control over the machine, use sockets for communications, can use a custom kernel, etc).
Friday, March 18, 2011
Speeding up Linux kernel compilation
These tools are:
- make -jn: The easier way to speed-up Linux kernel compilation is executing make with the option -j (jobs). This option specifies the number of parallel jobs that make will use to split the build process. Because the kernel Makefile have correct dependency information, one doesn't have to use make's default single process execution.
- ccache: When compiling it is common to use make clean to create a clean build of the project. Unfortunately this deletes all the information from previous compilations. The compiler cache (ccache) detects when the same compilation is doing again and looks in its cache for objects files so you don't have to generate them again.
- distcc: If you have more than one machine available, you can distribute your builds using distcc.
I ran a few experiments to measure compilation times with different configurations and compare performance improvement in each scenario.
The experiments where made in my development machine (Intel Core 2 Duo P870 2.53GHz - 4 GB DDR3 with Debian 6 Squeeze). Since I only had one machine I didn't try distcc.
Here are the results:
Using default make (with just one compilation job):
$ time make M=drivers/staging/ real 6m12.030s user 5m55.002s sys 0m30.818s
Using make with four compilation jobs:
$ time make -j4 M=drivers/staging/ real 3m39.378s user 6m27.852s sys 0m31.614s
Using make with one compilation job and ccache:
$ time make -M=drivers/staging/ real 0m46.364s user 0m35.042s sys 0m11.913s
Using make with four compilation jobs and ccache:
$ time make -j4 M=drivers/staging/ real 0m27.513s user 0m36.374s sys 0m11.465s
Using make with four compilation jobs and ccache we obtain a speedup of 8X which is really impressive. Also ccache statistics shows that direct cache hit was about 32%.
$ ccache -s cache directory /home/javier/.ccache cache hit (direct) 1091 cache hit (preprocessed) 24 cache miss 1 unsupported compiler option 52 no input file 25 files in cache 3455 cache size 43.7 Mbytes max cache size 1.0 Gbytes
Keep in mind that the first time you compile with ccache, your compilation will not be faster. It will even be slower because ccache has to populate its cache (i.e: its cache hit will be zero).
Saturday, January 1, 2011
Linux Device Drivers 3 examples updated
With this approach one can understand the ABIs, interfaces and helpers that the kernel offers to driver authors while having drivers for (pseudo) devices to play with.
A different approach is used in the book Essential Linux Device Drivers where the authors explain how drivers for real devices works. I think both approaches and books are complementary.
The problem is that LDD3 book is now a few years old and most of the example drivers do not compile in recent kernels. Also, many new changes were introduced in the kernel since 2.6.10. So examples for many ABIs are not covered in the book, like netlink sockets, threaded interrupt handlers, debugfs, etc.
I started a project to keep the LDD3 examples up-to-date with recent kernels and have plans to include more examples that cover more recent kernel features like the listed before.
The project can be found here.
Saturday, November 20, 2010
Configuraciones Git
Información sobre el autor:
$ git config --global user.name 'Javier Martinez Canillas'
$ git config --global user.email martinez.javier@gmail.com
Agregar colores a la salida:
$ git config --global color.diff auto
$ git config --global color.status auto
$ git config --global color.branch auto
$ git config --global color.interactive auto
Cambiar el editor por defecto a vi:
$ git config --global core.editor vim
La opción --global establece la configuración de manera global y no por repositorio.
Algunos comandos útiles
Revertir el último commit
$ git reset --soft HEAD^
Borrar archivos no versionados
$ git clean -f
Establecer el repositorio al estado del último commit
$ git reset --hard
Generar parches firmados con los últimos n commits (ejemplo: los últimos 2)
$ git format-patch -s -2
Saturday, November 13, 2010
@caos.uab.es
Como comente en mi ultima entrada, me mude a vivir a Barcelona y aunque me ofrecieron seguir en el proyecto como asesor remoto, decidí no continuar para poder dedicar todo mi tiempo y esfuerzo al Máster en Computación de Altas Prestaciones que empecé en la Universitat Autónoma de Barcelona.
Por lo tanto, ya no voy a escribir sobre desarrollo de aplicaciones web ni Java EE 6, lastimosamente no llegue a escribir ni el 10% de lo que quería, tengo una lista de +50 items sobre los que me hubiese gustado escribir.
De todas maneras, me pareció interesante y útil mantener un blog, además de tener un promedio de 600 visitas/mes. Así que voy a continuar con mi blog, solo que de ahora en más probablemente escriba sobre temas relacionados con mi máster, por ejemplo computación paralela, aplicaciones paralelas de pasos de mensajes, evaluación y predicción de rendimientos de aplicaciones paralelas, etc.
Sunday, July 18, 2010
mv /home/javier/ /espanya/barcelona/
Ya que es una plataforma nueva y no hay tanta documentación, me pareció que a alguien le podría servir lo que escribo.
Tengo una lista de temas que me gustaría tocar en el blog y no encuentro el tiempo, mas que nada es sobre JPA 2.0, JSF 2.0, JCDI 1.0, Facelets y Jquery, aunque también hay varios temas que involucran a la plataforma de Liferay e incluso desarrollo para el kernel de Linux.
Lastimosamente no tengo (o no encontré) mucho tiempo para escribir todo lo que quiero. Ahora mismo estoy muy ocupado con la logística para mi próximo viaje a Barcelona e incluso estic estudiant Català (hasta ahora lo que más me gustó es que la ñ no forma parte de su alfabeto). Espero encontrar un poco de tiempo libre para seguir escribiendo sobre todo lo que tengo pendiente de publicar.
Fins la propera!
Tuesday, April 20, 2010
Convertir imagen VirtualBox .vdi a Qemu .raw
En la mayoría de los blogs y tutoriales hablan de utilizar un binario llamada vditool, el problema es que aparentemente esta herramienta ya no esta soportada por VirtualBox.
Finalmente encontré como convertir la imagen en esta wiki http://en.wikibooks.org/wiki/QEMU/Images#Exchanging_images_with_VirtualBox.
Se utiliza el comando VboxManage
VBoxManage internalcommands converttoraw ubuntu.vdi ubuntu.raw
Ahora ya puedo montar mi imagen
mount -o loop,offset=32256 ubuntu.raw /mnt/diskimage/
y también iniciarla con QEMU
qemu -m 512 -hda ubuntu.raw -boot c
Thursday, March 25, 2010
CDI @ConversationScoped y JSF 2.0
En esta entrada vamos a ver que son las conversaciones en CDI y como podemos utilizarlas en aplicaciones JSF 2.0.
Siguiendo con la filosofía de este blog, el proyecto completo del ejemplo, puede ser descargado de http://kenai.com/projects/javiermartinezblog/downloads/download/JSFCDIConversations.zip.
Conversaciones y ámbito de conversación en CDI
Contexts and Dependency Injection (CDI) ofrece un conjunto de servicios que permiten que clases manejadas puedan existir durante el ciclo de vida de la aplicación en ámbitos bien definidos.
Uno de los ámbitos de CDI es el ámbito de conversación. En una entrada anterior, hablamos sobre los ámbitos de CDI, por lo que no voy a explicar cuales son en esta entrada.
El ámbito de conversación permite que las instancias existan durante mas de una petición. Una conversación puede estar compuesta de varias peticiones y pueden existir varias conversaciones por sesión.
Realmente, cada petición tiene asociada una conversación. Solamente que si la conversación no es marcada como "long-running" el contexto de conversación se libera al termino de la petición.
Por el contrario si la conversación fue marcada como "long-running" en alguna petición, el contexto de conversación se propaga a las siguientes peticiones hasta que este contexto sea destruido explícitamente.
Vemos que todas las peticiones tienen asociada una conversación, y esta puede estar en uno de estados:
- Transient: La conversación no fue iniciada explícitamente y de manera implícita existe durante el tiempo de vida de la petición.
- Long running: La conversación fue marcada como long running y existe hasta que sea finalizada explícitamente. Todas las demás peticiones van a estar dentro del ámbito de la conversación
Por lo tanto, las conversaciones se utilizan para mantener mantener un estado entre distintas peticiones. Para esto se tiene que establecer dos cosas:
1- Que el managed bean CDI tiene un ámbito de conversación.
2- Se tiene que marcar la conversación como "long-running".
A continuación vamos a ver como se realizan ambas cosas en CDI.
1 - Especificar que el ámbito de un managed bean CDI es de conversación:
CDI tiene varias anotaciones que definen tipos de ámbito, la anotacion para definir que una clase tiene un ámbito de conversación es:
@javax.enterprise.context.ConversationScoped
2- Marcar la conversación como long-running:
CDI cuenta con un bean para controlar el ciclo de vida de las conversaciones, esta clase es:
javax.enterprise.context.Conversation
Para que una conversación se propague a las demás peticiones, hay que marcarla como long-running.
Esto se hace primero obteniendo el bean que controla la conversación a través de inyección:
@Inject Conversation conversation;
y luego ejecutando el método begin() que marca la conversación como long-running:
converstaion.begin();
Para que la conversación se destruya al termino de la petición actual se ejecuta el método end():
converstaion.end();
Aplicación de ejemplo
Como se comento anteriormente, se ilustra el uso de conversaciones CDI en aplicaciones JSF 2.0, a través de un ejemplo.
La aplicacion de ejemplo es muy sencilla, solamente cuenta con dos paginas y lo único que hace es incrementar un contador cada vez que se ejecuta un botón. Además, cuenta con una segunda pagina que muestra el valor del contador.
El backing bean Controller tiene un ámbito de conversación, por lo que la clase tiene que ser decorada con la anotacion @SessionScoped y ademas tiene que implementar la interfaz Serializable (esto es requerido para cualquier managed bean CDI con un ámbito mayor que petición). A continuacion podemos ver las porciones relevantes de la clase Controller:
@javax.inject.Named
@javax.enterprise.context.ConversationScoped
public class Controller implements Serializable {
private int number = 0;
@Inject
private Conversation conversation;
/* getters, setters y metodos omitidos */
}
La clase tiene dos campos, number que representa el contador y es donde se guarda el estado de la cantidad de veces que se presiono el botón y conversation que es el bean que controla el ciclo de vida de la conversación y se obtiene a través de inyección.
La pagina principal index.html tiene un botón que al presionarlo ejecuta el método count() del backing bean Controller. Este método lo único que hace es incrementar el valor del campo number en uno. Además, un tag JSF
A continuación se pueden ver las porciones relevantes del código fuente de la pagina index.xhtml, así como los métodos del backing bean utilizados:
<h:commandButton action="#{controller.count}" value="Set count"/>
<h:outputLabel value="Count:"/>
<h:outputText value="#{controller.number}"/>
public void count()
{
number++;
}
public int getNumber()
{
return number;
}
Si la conversación no fue propagada a long-running, al termino de cada petición la conversación implícita asociada a la petición es destruida y se pierde el estado del backing bean. Por lo tanto también se pierde el contador y cada vez que se realice una solicitud, el contador tendra el mismo valor=1.
Por otro lado si marcamos la conversación como long-running, el estado del backing bean existe entre peticiones por lo que cada vez que se presiona el botón, el contador se incrementara en uno y la pagina va a desplegar el nuevo valor.
Por lo tanto la pagina index.html tambien cuenta con dos botones que permiten iniciar y terminar la conversacion, estos botones tienen asociados metodos en el backing bean que realizan estas funciones.
A continuacion se ilustra el codigo fuente de los botones, asi como los metodos en el backing bean que inician y terminan la conversacion:
<h:commandButton action="#{controller.beginConversation}" value="Begin Conversation"/>
<h:commandButton action="#{controller.endConversation}" value="End Conversation"/>
public void beginConversation()
{
if(conversation.isTransient())
conversation.begin();
}
public void endConversation()
{
if(!conversation.isTransient())
conversation.end();
}
Algo importante de destacar es que solamente se puede marcar una conversación como long-running si esta es transient. El querer marcar como long-running una conversación que ya lo es, se levanta una excepción. De igual manera solamente se puede terminar una conversación que es long-running.
Por este motivo primero se pregunta si la conversación isTransiente() o no, antes de tomar cualquier acción.
Además, la pagina principal cuenta con otro botón que permite ver el valor del contador en otra pagina result.xhtml. Esta pagina hace referencia a un backing bean (ResultController) CDI con ámbito de petición.
Como la conversación se propaga a las demás peticiones, el backing bean ResultController utiliza inyección para obtener la instancia del backing bean Controller que existe en su ámbito de petición.
A continuación se muestra el código fuente del backing bean ResultController:
@Named
@RequestScoped
public class ResultController {
private @Inject Controller controller;
public int getCount()
{
return controller.getNumber();
}
}
Eso es todo, en próximas entradas vamos a seguir viendo otras características de JSF 2.0, CDI 1.0 y Java EE 6 en general.
Wednesday, February 24, 2010
Validar formularios JSF 2.0 con Bean Validation 1.0
En esta entrada vamos a ver como integrar una tercera tecnología que forma parte de mi pila tecnológica ideal para desarrollo de aplicaciones web Java EE. Esta tecnología se define en el JSR 303 y se conoce como Bean Validation 1.0.
Bean Validation define un modelo de meta-datos basado en anotaciones y una API para realizar validaciones de JavaBeans.
Siguiendo la misma temática que en las entradas anteriores, voy a utilizar un pequeño ejemplo para demostrar las ventajas de Bean Validation.
El código fuente completo del ejemplo JSF-BeanValidation.zip, esta disponible en la plataforma kenai.com. Se creo un proyecto exclusivamente para albergar todos los ejemplos utilizados en este blog.
Aplicación de Ejemplo
La aplicación de ejemplo esta compuesta de tan solo una pantalla. Esta pantalla es un formulario que se utiliza para ingresar usuarios. El usuario solamente tiene dos campos, username y mail.
La aplicacion tiene tres componentes, el primero es una pagina Facelets que es la que presenta el formulario, los otros dos componentes son clases Java. Una representa al backing bean JSF y la otra es el modelo del usuario.
A continuación se ilustra la sección relevante del código fuente de la pagina
<h:form>
<h:panelGrid columns="3">
<h:outputLabel value="Username:" for="username"/>
<h:inputText id="username" value="#{userController.user.username}"/>
<h:message for="username" errorStyle="color: red" infoStyle="color: green"/>
<h:outputLabel value="E-mail:" for="email"/>
<h:inputText id="email" value="#{userController.user.email}"/>
<h:message for="email" errorStyle="color: red" infoStyle="color: green"/>
<h:commandLink action="#{userController.saveUser}" value="Save"/>
</h:panelGrid>
</h:form>
<h:panelGrid>
<h:messages globalOnly="true" errorStyle="color: red" infoStyle="color: green"/>
</h:panelGrid>
Como se puede ver, las cajas de texto están asociadas a campos de una instancia de la clase User.
Se accede a esta instancia a través de un campo del backing bean JSF userController.
El formulario cuenta con un botón que permite dar de alta al usuario. Para mantener a la aplicación lo mas simple posible, realmente no se van a almacenar los usuarios en ningún repositorio de datos, solamente se va a validar el modelo utilizando Bean Validation 1.0.
En una aplicación real, probablemente se utilizaría Java Persistence API 2.0 para realizar la persistencia, en entradas posteriores vamos a ver ejemplos de como integrar JPA con el resto de las tecnologías que vimos hasta ahora.
Validaciones con Bean Validation 1.0
La mayoría de las aplicaciones requieren validar la entrada de datos para permitir que el modelo de datos sea consistente.
Por ejemplo, si tenemos un formulario de alta de usuario en una aplicacion web, deberíamos validar que los datos ingresados sean los correctos. Además, tendríamos que notificar cuando un dato es incorrecto para que este pueda volver a ser ingresado correctamente.
En la practica, varios programadores forman parte del grupo encargado del desarrollo de una aplicación.
El desarrollador encargado de la lógica de negocios de un ingreso de usuario, no puede suponer que el desarrollador del formulario de alta de usuario realizó la validación de los campos en la capa de presentación.
Suponer esto puede hacer que la aplicación no sea robusta, ya que los datos ingresados podrían no ser correctos.
Por lo tanto el desarrollador de la lógica de negocios tiene que volver a validar que los campos sean correctos y este mismo escenario se repite para el desarrollador encargado de la capa de acceso a datos.
Es así como uno termina teniendo validaciones en cada capa de la aplicación como muestra la siguiente figura:

Este proceso no solo es propenso a errores, sino que duplica código y hace que la manutención del software sea mas difícil.
Por lo tanto, Bean Validation 1.0 es un esfuerzo por tener un único esquema de validación que se propague por todas las capas de la aplicacion.
La validación se realiza a nivel de modelo y se especifica de manera declarativa.
Bean Validation 1.0 tiene dos componentes:
- Un modelo declarativo y extensible de validación basado en anotaciones
- API estándar de consulta de meta-datos y validación en tiempo de ejecución
Como se comento anteriormente, para definir las restricciones de los campos se utilizan anotaciones, Bean Validation incluye varias anotaciones estándar que se encuentran en el paquete javax.validation.constraints. Las anotaciones estándar son:
- @AssertFalse: El campo Boolean tiene que ser false.
- @AssertTrue: El campo Boolean tiene que ser true.
- @DecimalMax: El campo tiene que ser un numero cuyo valor sea menor o igual a un máximo especificado.
- @DecimalMin: El campo tiene que ser un numero cuyo valor sea mayor o igual a un mínimo especificado.
- @Digits: El campo tiene que ser un numero cuyo valor se encuentre en un rango definido.
- @Future: El campo tiene que ser una fecha en un futuro.
- @Max: El campo tiene que ser un numero cuyo valor sea menor o igual a un máximo especificado.
- @Min: El campo tiene que ser un numero cuyo valor sea mayor o igual a un mínimo especificado.
- @NotNull: El campo no puede tener valor null.
- @Null: El campo tiene que tener valor null.
- @Past: El campo tiene que ser una fecha en el pasado.
- @Pattern: La cadena tiene que coincidir con el patrón de expresión regular especificado.
- @Size: El tamaño del campo tiene que estar dentro de un limite especificado (incluyente).
En la aplicación de ejemplo, la clase User utiliza Bean Validation para validar los campos, en el siguiente cuadro se ilustra el código fuente de la clase User:
public class User {
@NotNull
@Size(min=1,max=30)
private String username;
@Size(max=100)
@Pattern(regexp=".+@.+\\.[a-z]+")
private String email;
/*
getters y setters
omitidos
*/
}
La clase tiene dos campos username y email. Las validaciones especifican las siguientes restricciones para cada campo:
- username: El campo no puede ser nulo (@NotNull) y su tamaño tiene que estar dentro del limite 1 a 30 (@Size(min=1,max=30).
En el caso de una cadena, el tamaño se evalúa como longitud de la cadena, aunque tiene semántica distinta para otros tipos de datos (Collection, Array, Map, etc). - email: El tamaño del campo no puede ser mayor a 100 (@Size(max=100). Además, la cadena tiene que coincidir con el patrón definido por una expresión regular (@Pattern(regexp=".+@.+\\.[a-z]+")). Esta expresión regular especifica el formato válido para las direcciones de correo electrónico.
Como se comento anteriormente, Bean Validation esta compuesto de dos elementos. El primero es un modelo de meta-datos basado en anotaciones que se utiliza para decorar las clases y definir restricciones en los campos. Esto es lo que acabamos de ver.
El segundo componente es la API de consulta de meta-datos y validación. Esta API es la que se utiliza para verificar si una instancia de una clase cumple con todos los requisitos definidos con las anotaciones de Bean Validation.
Para validar las instancias de los JavaBeans se utiliza una implementación que implemente la interfaz:
javax.validation.Validator
La interfaz tiene un método validate() que es el que se utiliza para validar las instancias. Se obtiene una instancia de la implementación a través de un método factory:
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
A continuación, mostramos un ejemplo de como verificar si un usuario cumple con todas las restricciones. De no cumplir con alguna restricción, imprime en la salida estándar el nombre del campo que no cumple con la restricción y su respectivo mensaje de error.
Set<constraintviolation><user>> constraintViolations = Validation.buildDefaultValidatorFactory().getValidator().validate(this.user);
for(ConstraintViolation<user> constraintViolation : constraintViolations){
System.out.println(constraintViolation.getPropertyPath());
System.out.println(constraintViolation.getMessage());
}
Invocar explícitamente el método validate() debería ser la excepción y no la regla, ya que la idea es definir la validación en el modelo y utilizarla en todas las capas. Por lo tanto la mayoría de los frameworks de capa de presentación, tendrían que integrar automáticamente el mecanismo de validación de Bean Validation.
JavaServer Faces 2.0 lo integra automáticamente. Lo único que uno tiene que hacer es definir la validación en el JavaBean que contiene los campos asociados a los componentes GUI JSF y definir tags <message> o <messages> que procesen los mensajes de error.
Por ejemplo, en el formulario de alta de usuarios, hay una caja de texto asociada al campo username de la clase User:
<h:inputText id="username" value="#{userController.user.username}"/>
<h:message for="username" errorStyle="color: red" infoStyle="color: green"/>
Además, hay un tag <message> que esta asociado al <inputText> asociado al campo username.
Por lo tanto, si ocurre un error de validación en ese campo, JSF actualiza automáticamente el componente UI JSF correcto con el mensaje de error correspondiente.
Si queremos que los mensajes de error sean globales, entonces tenemos que definir un tag <messages> que no este asociado a ningún componente GUI.
<h:messages globalOnly="true" errorStyle="color: red" infoStyle="color: green"/>
Entonces, todos los mensajes de error de validación van a ser agregados a este componente UI, sin importar cual campo es el que no cumple con sus restricciones de validación.
Eso es todo lo que necesitamos para implementar validaciones de modelo en nuestras paginas JavaServer Faces 2.0.
Al hacer clic en el botón:
<h:commandLink action="#{userController.saveUser}" value="Save"/>
Primero se va a realizar la validación del modelo y si algún campo no cumple con sus restricciones de validación, se va a notificar mostrando los mensajes de error en los tags de mensajes.
Solamente si se cumplen todos los requisitos de validación, se va a ejecutar el método saveUser().
En esta entrada vimos un uso básico de Bean Validation, en próximas entradas vamos a ver conceptos mas avanzados como tener varios grupos de validación, crear restricciones de validación propias y el uso de Bean Validation para validar clases persistibles a través de JPA 2.0.
Thursday, February 18, 2010
Ejemplo Aplicación JSF 2.0 con CDI 1.0
Mi opción preferida es utilizar Contexts and Dependency Injection (CDI) para los backing beans JSF. Por lo tanto, en esta entrada voy a presentar un pequeño ejemplo de como utilizar JSF + CDI y voy a ilustrar algunas de las bondades de CDI.
No voy a explicar como configurar el proyecto para que utilice CDI, eso pueden verlo en esta entrada del blog.
El código fuente del ejemplo completo JSF-CDI.zip se encuentra en el proyecto creado, para los ejemplos del blog, en la plataforma kenai.com.
Aplicación de Ejemplo
La aplicacion de ejemplo es sumamente sencilla, esta compuesta solamente de dos paginas. La primera pagina tiene una caja de texto en el que se puede definir una entrada. Al presionar un botón se muestra en una etiqueta el texto ingresado. La segunda pagina permite ver el texto ingresado en la primera pagina y su función es ilustrar como se puede guardar el estado entre peticiones de distintas paginas.
JSF 2.0 utiliza como tecnología de vista Facelets ya que se integra mejor con JSF que JSP, por lo tanto las paginas del ejemplo son Facelets. A continuación se muestra la porción relevante del código fuente de ambas paginas:
<h:form>
<h:panelGrid columns="3">
<h:outputLabel value="Please enter an input:"/>
<h:inputText value="#{controller.input}"/>
<h:commandButton action="#{controller.setOutputAction}"
value="Set Output"/>
<h:outputLabel value="You entered: "/>
<h:outputText value="#{controller.output}"/>
</h:panelGrid>
<br/>
<h:commandButton action="/result" value="See output in another page"/>
</h:form>
<h:form>
<h:panelGrid columns="3">
<h:outputLabel value="You entered: "/>
<h:outputText value="#{resultController.output}"/>
</h:panelGrid>
<br/>
<h:commandButton action="/index" value="Go to main page"/>
</h:form>
No hay grandes cambios aquí, las paginas Facelets lucen igual que en JSF 1.2, están compuesta de componentes UI JSF y utilizan expresiones EL (Expression Language) para referirse a instancias de las clases que se utilizan como backing beans.
El cambio está en los backing beans, que son clases manejadas por CDI.
CDI como Backing Bean JSF
CDI ofrece un conjunto de servicios que permiten que clases manejadas puedan existir durante el ciclo de vida de la aplicación en ámbitos bien definidos.
Cuando un jar cuenta con un archivo beans.xml el contenedor registra todas las clases del jar con el motor CDI automáticamente. No es necesaria ninguna anotación para especificar que una clase tiene que ser manejada por CDI.
De todas maneras, si queremos que las instancias de las clases sean accesibles a través de expresiones EL, tenemos que decorar las clases con la anotación
@javax.inject.Named
De esta manera podemos acceder a los miembros de las clases manejadas a través de expresiones EL.
Por defecto el nombre de la instancia va a ser el nombre de la clase con su primera letra en minúscula, aunque podemos especificar otro nombre para referirnos a la instancia de la clase manejada. Ej:
@javax.inject.Named
public class Controller { ... }
#{controller.input}
@javax.inject.Named("testController")
public class Controller { ... }
#{testController.input}
CDI permite que las instancias existan en ámbitos bien definidos. Para marcar el ámbito de una clase manejada CDI, se utilizan anotaciones que se encuentran en el paquete javax.enterprise.context. Los ámbitos soportados por CDI son los siguientes:
- @ApplicationScoped (Ámbito de Aplicación): Las instancias existen durante todo el ciclo de vida de la aplicacion. Estas instancias son globales y accesibles desde cualquier sesión HTTP.
- @SessionScoped (Ámbito de Sesión): Las instancias son accesibles por todas las peticiones que ocurren durante una sesión HTTP.
- @ConverstationScoped (Ámbito de Conversación): Las instancias existen durante una conversación. Una conversación esta compuesta de varias peticiones y pueden existir varias conversaciones por sesión.
Realmente, cada petición tiene asociada una conversación. Solamente que si la conversación no es marcada como "long-running" el contexto de conversación se libera al termino de la petición.
Por el contrario si la conversación fue marcada como "long-running" en alguna petición, el contexto de conversación se propaga a las siguientes peticiones hasta que este contexto sea destruido explícitamente. - @RequestScoped (Ámbito de Petición): Las instancias solamente existen durante la peticion HTTP. Una vez que termina el ciclo de vida de la petición, también termina su contexto.
El ámbito de petición (@RequestScoped) es muy común, por lo que existe una anotación que incluye las anotaciones @Named y @RequestScoped, esta anotación es:
@javax.enterprise.inject.Model
En el ejemplo, queremos que la aplicacion tenga el siguiente comportamiento: cuando se presione el botón, se establezca el valor del campo asociado con la caja de texto, a la etiqueta de salida. Además, queremos que ese valor sea accesible desde otra pagina.
Con estos requerimientos, el valor tendría que poder existir durante varias peticiones HTTP. Por lo tanto la instancia del backing bean de la pagina principal tiene que ser anotada con una de las anotaciones @SessionScoped o @ConversationScoped, para que sea accesible durante varias peticiones.
Para este ejemplo se usa @SessionScoped para hacer mas claro el ejemplo y en próximas entradas se utilizara otro ejemplo para mostrar como funcionan las conversaciones en CDI.
Por lo tanto la clase backing bean de la pagina principal se llama Controller y esta definida de la siguiente manera:
@javax.inject.Named
@javax.enterprise.context.SessionScoped
public class Controller implements Serializable {
private String input;
private String output;
@EJB UpperCaseEJB testEJB;
/*
Resto de la declaración de la clase omitida.
*/
}
Implementa la interfaz Serializable porque CDI exige que las clases que se definen en un ámbito que no sea @RequestScoped, implementen esta interfaz.
Los campos input y output están asociados a los controles UI inputText y outputText respectivamente.
Las clases manejadas por CDI cuentan con varios servicios, la inyección es una de ellas y por eso utilizamos un EJB (UpperCaseEJB) para demostrar eso.
La instancia testEJB va a ser inyectada por el contenedor cuando se instancie la clase Controller.
Cuando hacemos click en el botón:
<h:commandButton action="#{controller.setOutputAction}"
value="Set Output"/>
se ejecuta el método setOutputAction() de la clase Controller, el método es el encargado de establecer el valor de la leyenda para mostrar en pantalla:
this.output = testEJB.toUpper(this.input);
El método toUpper() del EJB TestEJB convierte la cadena a mayúsculas, esto se utilizo solamente con fines académicos para demostrar lo sencillo que es utilizar un EJB desde una clase CDI.
Eso es todo, cuando se visualice la pagina nuevamente se va a ver el valor del campo output:
<h:outputLabel value="You entered: "/>
<h:outputText value="#{controller.output}"/>
Contextos e Inyección en CDI
La verdad que hasta ahora no vimos nada tan novedoso, después de todo los @ManagedBean JSF 2.0 también utilizan anotaciones para registrarse y definir su ámbito, son accesibles desde expresiones EL y también pueden inyectar instancias de EJBs.
Una de las novedades de CDI es su mecanismo de biyeccion, es decir la capacidad de publicar una instancia de una clase en algún ámbito y poder referirse a esa instancia desde otra clase.
En el ejemplo, queremos que se pueda ver el valor ingresado en la caja de texto, pero desde otra pagina.
Para esto, el backing bean de la pagina result.xhtml tiene que poder acceder a este valor.
Entonces, lo que queremos es publicar la instancia de la clase Controller que tiene este valor en un ámbito y que luego sea inyectado en la clase ResultController. Cuando se crea una instancia de la clase ResulController, automáticamente el contenedor deberia asignar la referencia a la instancia de la clase publicada.
La clase Controller tiene un ámbito de Sesión ya que fue decorada con la anotacion @SessionScoped.
Además, todas las clases son manejadas por CDI automáticamente, recordemos que la anotacion @Named es tan solo para hacer que la clase sea visible por las expresiones EL.
Por lo tanto, lo único que tenemos que hacer en la clase ResultController es inyectar una instancia de la clase Controller con la anotacion:
@javax.inject.Inject
Ej:
Eso es todo! El contenedor automáticamente inyecta una instancia de la clase Controller.
@Named
public class ResultController {
private @Inject Controller controller;
public String getOutput()
{
return controller.getOutput();
}
}
Por ultimo obtenemos el valor de output con el método getOutput().
Puede darse el caso de que tengamos mas de una instancia de una clase en particular. Por ejemplo, podríamos tener un sistema de control de versiones que tenga que comparar la diferencia entre dos archivos.
En estos casos tenemos que tener una manera para discriminar cual es la instancia que queremos inyectar.
Otros frameworks como Jboss Seam utilizan cadenas de texto como identificadores, pero esto es propenso a errores y los problemas se identifican recien en fase de ejecución.
Por el contrario, CDI utiliza un esquema de discriminación fuertemente tipado. Se utilizan anotaciones para especificar cual es la instancia que queremos inyectar.
En el ejemplo de los archivos tendríamos dos anotaciones, una que se podría llamar @Modificado y otra que podría llamarse @Base.
No solo tenemos que utilizar la anotacion a la hora de inyectar una instancia, sino que la publicación de una instancia ya no puede ser automática.
Tenemos que declarar explícitamente que tipo de instancia estamos publicando.
Por lo tanto, modificamos un poco la aplicacion de ejemplo para utilizar inyección fuertemente tipada. Lo primero que tenemos que hacer es definir una anotacion para discriminar a nuestra instancia que queremos publicar.
La anotacion que creamos se llama @SetupController, esta anotacion nos dice que el Controller que queremos inyectar es el utilizado para establecer el valor del input.
La manera de publicar instancias en CDI es definiendo un método cuyo valor de retorno este decorado con la anotacion:
@javax.enterprise.inject.Produces
Por ejemplo si quisiéramos publicar explícitamente nuestra instancia de la clase Controller podemos definir el siguiente método en la misma clase Controller:
public @Produces @SetupController Controller getController()
{
return this;
}
La semántica del método es que esta produciendo una instancia de una clase Controller con tipo @SetupController.
Cuando uno quiere inyectar una instancia de un tipo en particular, el contenedor busca en todas las instancias que existen en algún ámbito, aquella que cuenta con un método que produce el tipo de instancia que nosotros queremos inyectar.
Una vez que encuentra el método, lo ejecuta, obtiene el valor y lo inyecta en la instancia definida en nuestra clase.
Entonces, si quisiéramos inyectar la instancia de tipo @SetupController en nuestra clase ResultController, tendríamos que cambiar la declaración del campo a la siguiente:
private @Inject @SetupController Controller controller;
También podríamos haber publicado e inyectado tan solo el String que representaba nuestro output, pero me pareció mas interesante ver como se publicaba la propia clase Controller.
Eso es todo, en las siguientes entradas veremos como funcionan las conversaciones en CDI y otras cuestiones como agregar validaciones a nivel de modelo utilizando Bean Validation 1.0.
Monday, February 15, 2010
Utilizar Contexts and Dependency Injection (CDI) en proyectos JSF 2.0
Lo primero que tenemos que hacer es crear un proyecto web:

En el paso de elegir Frameworks, seleccionar JavaServer Faces. En la pestaña de Libraries seleccionar la librería JSF que viene por defecto (JSF 2.0) y en la pestaña de Configuration, seleccionar el lenguaje de pagina preferido como Facelets.

A diferencia de otros motores de manejo de beans, CDI no necesita de ninguna anotación para que una clase se registre y sea manejada. Por defecto todas las clases de un archivo (jar) son manejadas por CDI. La anotación @Named tan solo hace que los atributos de la clase sean accesible desde expresiones EL.
La búsqueda de clases y el registro de las mismas en el motor de CDI hace que el deploy de una aplicación sea mas lento. Por lo tanto, necesitamos de una manera de decirle al container si queremos o no usar CDI. La manera de especificar esto es creando un archivo xml vacío (beans.xml) en los directorios WEB-INF o META-INF.
La sola existencia del archivo WEB-INF/beans.xml o MET-INF/beans.xml ya activa CDI.
Por lo tanto, el ultimo paso consiste en crear el archivo WEB-INF/beans.xml.

Se puede por ejemplo tener varios jar, donde uno solo contiene un archivo beans.xml. De esta manera, el contenedor solo registraría las clases de este jar y no de los otros, haciendo que el deploy de la aplicacion sea mas rápido. Gavin King en su blog explica el porque de la necesidad del archivo beans.xml.
En la Figura podemos ver como queda la jerarquía de directorios del proyecto y como el archivo beans.xml esta vacío, la sola presencia del archivo ya es suficiente para activar el motor CDI.

Esto es todo, ahora lo único que tenemos que hacer es agregar clases y estas ya van a ser manejadas por CDI.
Si deployamos la aplicación, vamos a ver en el log del glassfish que se esta utilizando CDI, cuales son las clases manejadas y el ámbito de cada una.
En la siguiente entrada voy a explicar como utilizar las clases manejadas por CDI como backing beans JSF y como estas pueden ser accesibles desde expresiones EL en paginas Facelets. Para esto voy a utilizar un ejemplo que va a ilustrar las facilidades que nos brinda CDI.
Para hacer mas útil el blog, cree un proyecto en la plataforma Kenai donde voy a ir subiendo los ejemplos de las entradas que vaya publicando.
El primer ejemplo (JSF-CDI) es una pequeña aplicación que utiliza CDI Managed Beans para persistir el estado de los componentes UI de paginas JSF 2.0 con Facelets.
Actualización:
Si se realiza una actualizacion del Netbeans 6.8, ahora al crear un proyecto web, hay una opcion para habilitar CDI en el proyecto.

En la siguiente imagen podemos ver que en la sección de configuraciones, hay un checkbox para elegir si activar o no activar CDI. Por lo tanto lo único que se tiene que hacer es seleccionar esa opción y automáticamente se crea el archivo WEB-INF/beans.xml.
Thursday, February 11, 2010
JSF 2.0 Backing Bean: @ManagedBean o @Named
Antes de la llegada de Java EE 6 y JSF 2.0, la capa de presentación web no contaba con estas facilidades. Se tenia que editar varios XMLs para definir cuales eran las clases que tenían que ser manejadas por el motor de JavaServer Faces, las clases que se iban a utilizar para realizar conversiones, validaciones y la navegación entre paginas.
JSF 2.0 tiene varias mejores sobre JSF 1.x y entre la mas importante esta la posibilidad de decorar las clases que van a ser manejadas con anotaciones en vez de definirlas en archivos XML.
Lastimosamente no existe una sola manera de definir una clase (Bean) que va a ser manejada (Managed). De hecho Java EE 6 cuenta con tres maneras de definir una clase como un Managed Bean (cuatro de hecho, si tomamos en cuenta faces-config.xml).
Las tres maneras están definidas por distintas especificaciones, se utilizan distintas anotaciones, las prestaciones de cada manera son diferentes e incluso se manejan las clases por distintos contextos de ejecución.
El hecho de tener varias maneras de definir una misma cosa (Backing Bean JSF) hace que la curva de aprendizaje sea mas pronunciada para nuevos desarrolladores e puede incluso hacer mas complicado el desarrollo para programadores con experiencia (Dos anotaciones tienen el mismo nombre @ManagedBean).
A continuación analizamos cada una de las anotaciones:
JSF 2.0 Managed Bean (JSR 314)
JavaServer Faces 2.0 define sus propias anotaciones para registrar las clases que van a ser Managed Beans. La anotación es @javax.faces.bean.ManagedBean y nos libra de tener que especificar esta información en el archivo XML faces-config.xml.
También permite definir el ámbito de las clases manejadas y las hace accesibles desde expresiones EL.
Ej:
@javax.faces.bean.ManagedBean
@javax.faces.bean.SessionScoped
public class Bean implements Serializable{ ... }
También existe otra anotación que permite inyectar en una referencia una instancia de una clase que este siendo manejada en algún ámbito.
Ej:
@javax.faces.bean.ManagedProperty(value="#{bean}")
private Bean bean;
public void setBean(Bean bean)
{
this.bean = bean;
}
Cuando se instancia la clase que contiene el campo bean, se evalúa la expresión y se llama al método setBean().
Managed Bean 1.0 (JSR 316)
Debido a que existían muchos modelos de componentes para definir clases manejadas (JSF Managed Beans, EJB, CDI, etc), el grupo de trabajo de EJB 3.1 definio un modelo de componentes general. Se definió una anotación (@javax.annotation.ManagedBean) que marca a una clase como un "ManagedBean". Estas clases automáticamente cuentan con un conjunto de servicios básicos (inyección de recursos, callbacks del ciclo de vida e interceptores).
Lastimosamente se eligió el mismo nombre para definir ambos tipos de clases manejadas (Managed Bean 1.0 y JavaServer Faces 2.0).
Otro problema de los ManagedBeans es que no son accesibles desde expresiones EL. La única razón por la que se incluyo en esta lista es para evitar que uno se confunda y utilice la anotación:
@javax.annotation.ManagedBean
en vez de
@javax.faces.bean.ManagedBean
Context and Dependency Injection 1.0 (JSR 299)
Context and Dependency Injection (CDI) es un conjunto de servicios que permiten que clases manejadas puedan existir durante el ciclo de vida de la aplicación en contextos bien definidos.
Es otra manera de registrar POJOs como clases manejadas. CDI tiene dos ventajas sobre los otros enfoques:
- JSF 2.0 Managed Beans esta muy orientado a un entorno de ejecución web. Al igual que los ManagedBean de JSF 316, CDI pretende ser mas general por lo que ofrece mas prestaciones que los JSF Managed Beans.
- CDI permite crear objetos (outjection) e inyectar recursos (injection) en varios ámbitos y utiliza tipos en vez de expresiones, además las clases manejadas por CDI pueden ser accedidas desde expresiones EL (a diferencia de los ManagedBeans JSR 316).
La anotación que se utiliza para registrar una clase en CDI es @javax.inject.Named.
Ej:
@javax.inject.Named
@javax.enterprise.context.SessionScoped
public class Controller implements Serializable {...}
Para inyectar una instancia de algún ámbito en una referencia se utiliza el tipo.
Ej:
@Inject private Controller controller;
La inyección es fuertemente tipada y se verifica en tiempo de compilación, no en tiempo de ejecución.
Personalmente creo que CDI es la mejor manera de utilizar clases manejadas en Java EE 6, en próximas entradas veremos cuales son los requisitos para utilizar CDI Managed Beans con el stack de Sun y cuales son sus ventajas.
Tuesday, February 2, 2010
Pila de Tecnologías para proyecto Web Java EE 6
Mientras mas complejo es el universo de Java, mas se necesita de especialización. El principal problema cuando uno inicia un proyecto Java es el seleccionar frameworks, IDE, build tool y librerías que se van a utilizar.
JSF o Seam?
Spring o EJB3?
JPA o Hibernate?
Eclipse o Netbeans?
Glassfish o Jboss?
Ant o Maven?
Nos encontramos con estas preguntas y necesitamos las respuestas. No creo que exista una respuesta correcta, ya que siempre va a depender de varios factores (requerimientos del software a desarrollar, conocimiento previo del equipo de desarrollo, imposición de cierta plataforma, etc).
De todas maneras, las opciones que uno elija van a tener incidencia en el proceso de desarrollo.
A continuación voy a detallar la pila tecnológica que yo creo es la mas adecuada para un proyecto nuevo en el que se va a desarrollar una aplicación Java web empresarial.
- Capa de presentación: JSF 2.0 + Facelets + CDI 1.0 + PrimeFaces
- Capa de lógica de negocios: EJB 3.1
- Capa de persistencia: JPA 2.0
- Validaciones: Bean Validation 1.0
- Web Services: JAX-WS + JAX-RS
- Reportes: JasperReports
- Servidor de Aplicaciones: Glassfish V3
- IDE: Netbeans 6.8
- Build tool: Ant
La mayoría de estas tecnologías son estándares y forman parte de la plataforma Java EE 6.
Esta decisión es básicamente por dos motivos:
Al utilizar una pila tecnológica de un mismo vendor, uno no pierde el tiempo en integrar varias tecnologías. Es el vendor el que se encarga de que todo se integre de la mejor manera y que la experiencia del desarrollador sea lo mas placentera posible.
El uso de estándares maximiza las probabilidades de que el framework utilizado tenga una comunidad, vaya creciendo, mejorando y no se vuelva obsoleto. Además, nos da cierta garantía para migrar a otro vendor en el caso que necesitemos.
En los próximas entradas, voy a explicar el porque de cada tecnología, por ejemplo CDI Managed Beans y no JSF Managed Beans, etc.