Categorías del Tutorial

icono_twiter
Alejandro Pérez García

Alejandro es socio fundador de Autentia y nuestro experto en J2EE, Linux y optimización de aplicaciones empresariales.

Ingeniero en Informática y Certified ScrumMaster

Si te gusta lo que ves, puedes contratarle para darte ayuda con soporte experto, impartir cursos presenciales en tu empresa o para que realicemos tus proyectos como factoría (Madrid).
Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2007-07-05

Tutorial visitado 23.589 veces Descargar en PDF
Como hacer un componente de JSF

Como hacer un componente de JSF

Creación: 27-06-2007



Índice de contenidos




1. Introducción

Ya hemos visto algunas cosas sobre JSF (http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=jsf). Básicamente podríamos decir que se trata de un estándar que ya forma parte de la especificación de Java EE 5, donde el desarrollo se hace en base a componentes.

Lo ideal es usar los componentes estándar o usar librerías de componentes ya construidas, como Tomahawk (http://myfaces.apache.org/tomahawk/) o ICEfaces (http://www.icesoft.com/products/icefaces.html). Pero en algunas ocasiones no encontraremos ningún componente que cubra nuestras necesidades.

Para estas ocasiones siempre nos queda la opción de construirnos nuestros propios componentes. Esto es lo que vamos a ver en este tutorial.

En concreto vamos a construir un componente que, indicándole un POJO, nos pinte un formulario con una etiqueta y un campo de entrada para cada una de las propiedades de tipo String de ese POJO.

¡¡¡ Atención, el componente que vamos a construir sólo pretende ilustrar la construcción de un componente, pero todavía le quedará mucho para poder ser usando en producción !!!

Y ya, entrando en harina, podemos adelantar que para la construcción de un componente vamos a desarrollar tres piezas:

  • el componente: esta clase es realmente el componente, y es donde estará implementada la lógica asociada.

  • el render: es la clase que se encarga de pintar el componente y de recuperar la información introducida por el usuario para "inyectarla" en el componente. El render está asociado a un medio concreto (web, wap, ...), mientras el componente es único. Es decir, podemos tener varios render para un mismo componente, o incluso reescribir los render si queremos cambiar el "como se pinta".

  • el tag: lo normal (aunque no obligatorio) es que nuestro componente lo queramos usar cómodamente en páginas JSP. El tag será la clase que implemente eso, una etiquetad de JSP.

En los siguientes apartados se ira viendo como construimos cada una de estas piezas.

Vamos a aprovechar y vamos a recordar el ciclo de vida de JSF. Para el desarrollo en JSF (bien sea de aplicaciones o de componentes) es fundamental comprender y dominar las 6 fases del ciclo de vida de JSF:

  1. Restore view: Se reconstruye el árbol de componentes.

  2. Apply request values: Se leen los valores de la request y se aplican sobre los componentes. En este momento es cuando se llama a los converters. Si hay algún error en la conversión se irá directamente a la fase "render response". Si un componente tiene "immediate=true" su validación (y el procesamiento de los eventos provocados por esa validación) se hará en esta fase .

  3. Process validations: se validan todos los componentes (todos los que tienen "immediate=false", ya que los que lo tienen a true ya se validaron en la fase anterior). Si falla alguna de las validaciones se irá directamente a la fase "render response".

  4. Update model values: Los valores de los back beans de JSF se actualizan con los valores que hasta ahora estaban guardados sólo en los componentes.

  5. Invoke application: Se invoca a los métodos de los back beans.

  6. Render response: se pinta la respuesta al usuario. Se pinta el árbol de componentes.

Podéis encontrar más información en http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSFIntro10.html.

Aquí podéis encontrar el código completo de las tres clases necesarias para construir el componente.



2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Asus G1 (Core 2 Duo a 2.1 GHz, 2048 MB RAM, 120 GB HD).

  • Sistema Operativo: GNU / Linux, Debian (unstable), Kernel 2.6.21, KDE 3.5

  • Máquina Virtual Java: JDK 1.6.0-b105 de Sun Microsystems

  • Eclipse 3.2.2

  • MyFaces 1.1.5

  • Maven 2.0.7



3. El componente

A la hora de construir un componente debemos fijarnos si ya hay alguno que hace algo parecido, ya sea dentro del estándar, o de alguna librería que hayamos adquirido. Si ya tenemos un componente que hace algo parecido la mejor opción suele ser que nuestra clase extienda de ese componente para aprovechar las funcionalidades del padre. Si no encontramos ningún componente que podamos reutilizar tendremos que extender de la clase javax.faces.component.UIComponentBase.

En nuestro ejemplo vamos usar el segundo camino, extenderemos la clase UIComponentBase. Vamos a ir viendo paso a paso esta clase (recordar que en al final de la introducción tenéis acceso un tar.gz con el código completo):

        public static final String COMPONENT_TYPE = FormBeanComponent.class.getName();
        public static final String DEFAULT_RENDERER_TYPE = HtmlFormBeanRenderer.class.getName();

Estas dos constantes son cadena arbitrarias, aunque hemos decidido usar los nombres de las clases, se podría haber puesto cualquier otra cosa. Luego las utilizaremos para determinar el render que se tiene que usar para pintar el componente.

        private ValueBinding beanBinding = null;

En este atributo guardaremos el bean a partir del cual vamos a pintar el formulario, y donde se guardaran los valores introducidos por el usuario (en la fase "update model values"). Es de tipo ValueBinding para poder usar lenguaje de expresiones de JSF para darle valor en la JSP.

        private Map<String, String> localValues = new HashMap<String, String>();

Según hemos visto en el ciclo de vida, los valores de la request se almacenan en el componente hasta alcanzar la fase "update model values". Este atributo lo usaremos para guardar esos valores recuperados de la request. Ya hemos dicho que nuestro componente sólo trabajará con las propiedades de tipo String, así que en este mapa guardaremos como clave el nombre de la propiedad y como valor, el valor introducido por el usuario.

        public FormBeanComponent() {
                setRendererType(DEFAULT_RENDERER_TYPE);
        }

Constructor de la clase. Es importante llamar a setRenderType(), este es un método de nuestro padre que permite definir cual será el identificador del render a usar. Si no hacemos esto luego JSF no será capaz de elegir el render apropiado para pintar el componente.

        @Override
        public String getFamily() {
                return COMPONENT_TYPE;
        }

Este es el único método que estamos obligados a implementar por extender la clase UIComponentBase. Este método devuelve el identificador de la familia a la que pertenece este componente. JSF, en función de este valor y del tipo de render (lo hemos definido en el constructor), elegirá el render apropiado para pintar este componente.

        public Object getBean() {
                final Object bean = beanBinding.getValue(FacesContext.getCurrentInstance());
                return bean;
        }

Este método devuelve el POJO que hemos asociado al componente (el POJO que usaremos para pintar el formulario y posteriormente para guardar los valores). Nótese como se extrae el valor del atributo beanBinding (dijimos que este atributo va a hacer referencia al POJO mediante lenguaje de expresiones de JSF). También hay "setter" correspondiente para fijar el valor del POJO (se puede ver en el código completo).

        @Override
        public void restoreState(FacesContext context, Object state) {
                final Object values[] = (Object[])state;
                super.restoreState(context, values[0]);
                beanBinding = (ValueBinding)restoreAttachedState(FacesContext.getCurrentInstance(), values[1]);
        }

        @Override
        public Object saveState(FacesContext context) {
                List<Object> state = new ArrayList<Object>();
                state.add( super.saveState(context) );
                state.add( saveAttachedState( FacesContext.getCurrentInstance(), beanBinding ) );
                return state.toArray();
        }

Estos dos métodos vienen de la interfaz javax.faces.component.StateHolder. La implementación de esta interfaz permite a un componente mantener valores entre diferentes request. Esto es necesario porque en cada request se reconstruye todo el árbol de componentes (recordar la fase "restore view"), es decir se crean nuevas instancias de cada componente. Para nuestro componente es importante guardar el POJO al que se está haciendo referencia. Como estamos sobreescribiendo los métodos de nuestro padre, es muy importante que no se nos olvide llamar a super.

        @Override
        public void processUpdates(FacesContext facesContext) {
                final Object bean = getBean();
                final Class<?> clazz = bean.getClass();
                final Class[] parameterTypes = { String.class };

                for (Map.Entry newValue : localValues.entrySet()) {
                        final String key = newValue.getKey().toString();
                        final String setterName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1);
                        Method setterMethod;
                        try {
                                final Object[] setterArguments = { newValue.getValue() };
                                setterMethod = clazz.getMethod(setterName, parameterTypes );
                                setterMethod.invoke(bean, setterArguments);
                                
                        } catch (Exception e) {
                                e.printStackTrace();
                        }
                }
        }

Este método se va a invocar en la fase de "update model values", y es el que se tiene que encargar de actualizar el back bean (en nuestro caso el POJO que tenemos referenciado con el atributo beanBinding) con los valores que están guardados localmente en el componente (en nuestro caso los valores que tenemos en el atributo localVlaues). Igual que esté método, tenemos métodos similares por si tenemos que hacer cosas en el resto de las fases (processRestoreState, processDecodes, processValidators, ...).

El código lo que hace es recorrer el mapa con los valores locales que ha recogido el componente de la request y buscar esas propiedades en el POJO por introspección. En cualquier caso no es más que un ejemplo y no importa tanto su implementación como que quede clara la responsabilidad del método, y que este se invoca en la fase "update model values".

Con esto hemos terminado con el componente (se han omitido algunos getter y setter que podéis ver en el código completo). Cabría destacar especialmente los métodos para guardar el estado del componente entre request (restoreState, saveState) y el método que actualiza los valores de los back beans (processUpdates).



4. El render

Esta clase será la que se encargue de recuperar los parámetros de la request http y pasárselos al componente, y de consultar el componente para "pintar" el HTML. Esto lo podría haber hecho el propio componente pero no es recomendable. Lo bueno de los componentes de JSF es que podemos reutilizarlos para diferentes dispositivos, y esto lo conseguiremos teniendo diferentes renders para un sólo componente.

Para implementar un render extenderemos de la clase javax.faces.render.Renderer.

        @Override
        public void decode(FacesContext facesContext, UIComponent uiComponent) {
            final FormBeanComponent formBeanComponent = (FormBeanComponent)uiComponent;
                
            // Se va a usar el POJO asociado al componente para buscar las propiedades,
            // pero los valores recogidos de la request se almacenaran en la variable local.
            final Object componentValue = formBeanComponent.getBean();
            final Map<String, String> localValues = formBeanComponent.getLocalValues();
            localValues.clear();
                
            final Class<?> clazz = componentValue.getClass();
            final Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                final String methodName = method.getName();
                final String propertyName = methodName.substring(3);
                        
                if (method.getParameterTypes().length == 0 
                        && method.getReturnType() == String.class 
                        && methodName.startsWith("get")) {
                    // Sabemos que es un geter, ahora hay que comprobar si existe el setter equivalente
                    final Class[] parameterTypes = { method.getReturnType() };
                    final Method setterMethod;
                    try {
                        setterMethod = clazz.getMethod("set" + propertyName, parameterTypes);
                    } catch (Exception e) {
                        continue; // no existe setter equivalente, así que seguimos buscando propiedades.
                    }
                    if (setterMethod.getReturnType() != Void.TYPE) {
                        continue; // no es realmente un setter ya que un setter no debería tener tipo de retorno.
                    }
                                
                    // Se busca en la request el nombre de la propiedad
                    final String requestParameterName 
                            = propertyName.substring(0,1).toLowerCase() + propertyName.substring(1);
                    final String requestParameter 
                            = (String)JsfUtils.getRequestParametersMap().get(requestParameterName);
                                
                    localValues.put(requestParameterName, requestParameter);
                }
            }
        }

Este método decode se encarga de extraer los parámetros de la request de http, y guardarlos en la variable local del componente. Igual que antes, no es tan importante la implementación del algoritmo, como que quede claro que este método es el que se llama en la fase de "apply request values" para guardar los parámetros de la request en el componente.

        @Override
        public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {
            final ResponseWriter out = facesContext.getResponseWriter();
            final FormBeanComponent formBeanComponent = (FormBeanComponent)uiComponent;
            final Object bean = formBeanComponent.getBean();
            final Class<?> clazz = bean.getClass();
            final Object[] getterArguments = {}; 

            out.startElement("table", null);
            for (Method method : clazz.getMethods()) {
                final String methodName = method.getName();
                final String propertyName = methodName.substring(3);
                        
                if (method.getParameterTypes().length == 0 
                        && method.getReturnType() == String.class 
                        && methodName.startsWith("get")) {
                    // Sabemos que es un geter, ahora hay que comprobar si existe el setter equivalente
                    Class[] parameterTypes = { method.getReturnType() };
                    final Method setterMethod;
                    try {
                        setterMethod = clazz.getMethod("set" + propertyName, parameterTypes);
                    } catch (Exception e) {
                        continue; // no existe setter equivalente, así que seguimos buscando propiedades.
                    }
                    final Class setterReturnType = setterMethod.getReturnType();
                    if (setterReturnType != Void.TYPE) {
                        continue; // no es realmente un setter ya que un setter no debería tener tipo de retorno.
                    }
                                
                    // Se vuelca en la salida el campo de entrada para la propiedad
                    final String outParameterName 
                            = propertyName.substring(0,1).toLowerCase() + propertyName.substring(1);
                    out.startElement("tr", null);
                    out.startElement("td", null);
                    out.startElement("label", null);
                    out.writeAttribute("for", outParameterName, null);
                    out.writeText(outParameterName, null);
                    out.endElement("label");
                    out.endElement("td");
                    out.startElement("td", null);
                    out.startElement("input", null);
                    out.writeAttribute("type", "text", null);
                    out.writeAttribute("name", outParameterName, null);
                    try {
                        final String value = (String)method.invoke(bean, getterArguments);
                            out.writeAttribute("value", value, null);
                    } catch (Exception e) {
                        throw new IOException(e);
                    }
                    out.endElement("input");
                    out.endElement("td");
                    out.endElement("tr");
                }
            }
            out.endElement("table");
        }

Para "pintar" el componente tenemos los métodos encodeBegin, encodeChildren y encodeEnd. Estos tres métodos permiten pintar la etiqueta inicial, pintar el cuerpo o etiquetas anidadas, y pintar el final de la etiqueta. En los casos en los que no es necesario hacer esta separación (como en nuestro caso), se mete todo el código en el método encodeEnd. Nuevamente recordar que no es más que un ejemplo.



5. El tag

Como último paso vamos a crear un tag de JSP para poder usar cómodamente nuestro componente en una página JSP. Para ello vamos a extender de la clase javax.faces.webapp.UIComponentTag. Veamos como queda nuestra clase:

        private String bean = null;

El tag admitirá un parámetro donde se recogerá el lenguaje de expresiones de JSF que indica el POJO que se usará en el componente. En el atributo bean será donde guardemos la cadena con este lenguaje de expresiones.

        @Override
        public String getComponentType() {
                return FormBeanComponent.COMPONENT_TYPE;
        }

        @Override
        public String getRendererType() {
                return FormBeanComponent.DEFAULT_RENDERER_TYPE;
        }

Estos dos métodos estamos obligados a sobreescribirlos por extender de UIComponent. getComponentType() sirve para indicar la familia del componente, y getRenderType() el tipo de render que sabe pintarlo. Estos dos métodos determinarán el render que hay que usar para pintar el componente cuando se procese el tag. Se están usando las constantes que habíamos definido en la clase del componente.

        @Override
        protected void setProperties(UIComponent component) {
            super.setProperties(component);
                
            final Application application = FacesContext.getCurrentInstance().getApplication();
            final FormBeanComponent formBeanComponent = (FormBeanComponent)component;
                
            if (bean != null) {
                // Con isValueReference comprobamos si el valor del atributo puesto
                // en la JSP se trata de EL (Expresion Languaje #{ } )
                if (isValueReference(bean)) { 
                    formBeanComponent.setBeanBinding(application.createValueBinding(bean));
                }
            }
        }

Sobreescribimos este método para procesar los parámetros indicados en el tag en la JSP. Se comprueba que el atributo bean tenga valor, y que este realmente esté apuntando a un back bean. No se nos debe olvidar llamar a super. Nótese como el parámetro component es nuestro componente ya creado por JSF.

        @Override
        public void release() {
                super.release();
                bean = null;
        }

Los tags se reutilizan, así que es muy conveniente sobreescribir el método release() para no encontrarnos con sorpresas.

Toda librería de tags necesita un descriptor (*.tld) para que el servidor sepa manejarlo. Para nuestro tag tendremos el siguiente descriptor:

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

<!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>1.0</tlib-version>
        <jsp-version>1.2</jsp-version>
        <short-name>LibrerÃa de etiquetas de validación para JSF</short-name>
        <uri>app-jsf-validator-taglibrary_1.0</uri>
        <display-name>app-jsf-validator</display-name>
        <description>Etiquetas para JSF</description>

        <tag>
                <name>beanFormComponent</name>
                <tag-class>com.app.web.jsf.component.FormBeanTag</tag-class>
                <body-content>JSP</body-content>
                <description>
                        Etiqueta para usar el componente personalizado en la una JSP
                </description>
                <attribute>
                        <name>bean</name>
                        <required>true</required>
                        <rtexprvalue>false</rtexprvalue>
                        <type>String</type>
                </attribute>
        </tag>
</taglib>

Básicamente estamos indicando el nombre del tag "beanFormComponent", la clase que lo implementa, y que tiene un atributo "bean" de tipo String que es obligatorio.



6. Ejemplo de uso

Ya tenemos todas las piezas para usar nuestro componente a medida. Una JSP de ejemplo podría ser la siguiente:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t" %>
<%@ taglib uri="app-jsf-tags" prefix="a" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<f:view>
<f:loadBundle basename="MessageResources" var="msg"/>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>

<body>

<h:form id="form">
    <a:beanFormComponent bean="#{contact}" />

    <h:commandButton id="button" action="#{contactCtrl.saveContact}" value="#{msg['btn.save']}" />
</h:form>

</body>

</f:view>

</html>

Arriba se incluye el taglib uri="app-jsf-tags" (para ver el significado de esta uri ver el web.xml del tar.gz con el código completo), y le damos el prefijo "a". Ahora para usar la etiqueta sólo tenemos que hacer:

    <a:beanFormComponent bean="#{contact}" />

Donde "#{contact}" es el lenguaje de expresiones de JSF que indica el POJO que vamos a vincular al componente. Ojo "contact" deberá existir en algún ámbito (request, session, aplicación), o estar definido el faces-config.xml.

Y hablando del faces-config.xml, no se nos puede olvidar dar de alta en este fichero tanto el componente como el render que lo va a pintar:

        <!-- components -->
        <component>
                <component-type>com.app.web.jsf.component.FormBeanComponent</component-type>
                <component-class>com.app.web.jsf.component.FormBeanComponent</component-class>
        </component>

        <!-- renderkit -->
        <render-kit>
                <renderer>
                        <component-family>com.app.web.jsf.component.FormBeanComponent</component-family>
                        <renderer-type>com.app.web.jsf.component.HtmlFormBeanRenderer</renderer-type>
                        <renderer-class>com.app.web.jsf.component.HtmlFormBeanRenderer</renderer-class>
                </renderer>
        </render-kit>

Primero hemos dado de alta el componente hemos definido la clase que lo implementa y el tipo del componente (corresponde con la constante COMPONENT_TYPE que habíamos definido en la clase FormBeanComponent).

Luego damos de alta el render, indicamos su clase, el tipo de render (corresponde con la constante DEFAULT_RENDER_TYPE que habíamos definido en la clase FormBeanComponent), y la familia de componentes que sabe pintar (corresponde con la constante COMPONENT_TYPE que habíamos definido en la clase FormBeanComponent).



7. Conclusiones

Recordamos que este componente que hemos construido es simplemente un ejemplo, y que hay cosas que no se han tenido en cuenta (como por ejemplo las validaciones, o uso de los converters). Cuando implementéis vuestros componentes tenéis que prestar mucha atención sobre el ciclo de vida completo.

Y ya sabéis, intentar usar algo que ya exista (siempre se más fácil y más barato integrar que desarrollar), construir a partir de algo que ya exista, y si no os queda más remedio hacerlo de cero. Y siempre tendréis una cuarta opción: contactar con nosotros en www.autentia.com para que os echemos una mano ;)



8. Sobre el autor

Alejandro Pérez García, Ingeniero en Informática (especialidad de Ingeniería del Software)

Socio fundador de Autentia (Formación, Consultoría, Desarrollo de sistemas transaccionales)

mailto:alejandropg@autentia.com

Autentia Real Business Solutions S.L. - "Soporte a Desarrollo"

http://www.autentia.com



A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Fecha publicación: 2011-05-27-17:30:02

Autor: edelgadocrc

Tengo una consulta, como hago para integrar esto a paginas xhtml, segun otro articulo publicado aqui mismo (http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=migrateJSF2Facelets) , hice todos los pasos, pero no encuentro la forma que los componentes en el "xhtml" me desplieque las propuedades que necesito asignarles, solo me despliequa el id y yo tengo varias propiedades en el tld (name, values, label,requerida, etc.) y programadas en una clase "InputEntryTag" pero esto no lo puedo habilitar ejmp de como se me muestra acutalmenete en le xhtml: "<cs:inputEntry id="compoente1"/>"

Fecha publicación: 2011-01-04-01:51:17

Autor: rart3001

Saludos, Muy bueno el ejemplo,

Ahora tengo una duda siguiendo tu ejemplo cree mi propio componente, el cual funciona perfecto, pero se me presento un detalle, que a incluirlo en una pagina .xhmtl con facelets el componente no funciona correctamente, ya que por lo visto el facelest no ejecuta la clase manejadora del tag es decir la que hereda de (javax.faces.webapp.UIComponentTag) si no que trabaja directamente con el component y el renderer directamente, pero a no utilizar esta clase no ejecuta el metodo setProperties(UIComponent component); y este es el cual realiza el seteo de los atributos del componente, y hace que en el renderer de un error de NULL al no ser seteado los atributos, si tienes alguna sugerencia, seria de mucha hayuda y gracias de antemano

Fecha publicación: 2009-09-04-11:57:04

Autor:

[Juan Carlos] Corregi esos problemas de la siguiente manera (no me dio tiempo de reemplazar los nombres de variables y archivos de acuerdo al tutorial, asi que estoy copiando con los nombres de archivos y variables que yo use en mi implementacion): &lt;br&gt; En el archivo web.xml, se debe añadir la referencia al tld para poder usarlo en la pagina jsp &lt;br&gt; &lt;taglib&gt;&lt;br&gt; &lt;taglib-uri&gt;componente-tags&lt;/taglib-uri&gt;&lt;br&gt; &lt;taglib-location&gt;/WEB-INF/tld/componente-tags.tld&lt;/taglib-location&gt;&lt;br&gt; &lt;/taglib&gt;&lt;br&gt; &lt;br&gt; En faces-config.xml se deben definir dos beans que se usan en la pagina que usa el componente personalizado&lt;br&gt; &lt;managed-bean&gt;&lt;br&gt; &lt;managed-bean-name&gt;contact&lt;/managed-bean-name&gt;&lt;br&gt; &lt;managed-bean-class&gt;clases.AlgunBean&lt;/managed-bean-class&gt;&lt;br&gt; &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt;&lt;br&gt; &lt;/managed-bean&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt; &lt;managed-bean&gt;&lt;br&gt; &lt;managed-bean-name&gt;contactCtrl&lt;/managed-bean-name&gt;&lt;br&gt; &lt;managed-bean-class&gt;clases.admContact&lt;/managed-bean-class&gt;&lt;br&gt; &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt;&lt;br&gt; &lt;/managed-bean&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt; La clase AlgunBean.java solo tendra sus propiedades y los respectivos metodos set y get&lt;br&gt; &lt;br&gt; La clase admContact debe implementar el metodo saveContact donde se realizan los algoritmos que cada quien requiera, pero ya se puede sacar de la session en bean registrado como contact con los datos que ingreso el usuario.&lt;br&gt; &lt;br&gt; Tambien elimine la etiqueta&lt;br&gt; &lt;br&gt; &lt;f:loadBundle basename="MessageResources" var="msg"/&gt;&lt;br&gt; &lt;br&gt; y remplace su referencia en el boton de esta manera:&lt;br&gt; &lt;br&gt; &lt;h:commandButton id="button" action="#{contactCtrl.saveContact}" value="Enviar" /&gt;&lt

Fecha publicación: 2009-09-04-11:53:42

Autor:

[Juan Carlos] Corregi esos problemas de la siguiente manera (no me dio tiempo de reemplazar los nombres de variables y archivos de acuerdo al tutorial, asi que estoy copiando con los nombres de archivos y variables que yo use en mi implementacion): En el archivo web.xml, se debe añadir la referencia al tld para poder usarlo en la pagina jsp &lt;taglib&gt; &lt;taglib-uri&gt;componente-tags&lt;/taglib-uri&gt; &lt;taglib-location&gt;/WEB-INF/tld/componente-tags.tld&lt;/taglib-location&gt; &lt;/taglib&gt; En faces-config.xml se deben definir dos beans que se usan en la pagina que usa el componente personalizado &lt;managed-bean&gt; &lt;managed-bean-name&gt;contact&lt;/managed-bean-name&gt; &lt;managed-bean-class&gt;clases.AlgunBean&lt;/managed-bean-class&gt; &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt; &lt;/managed-bean&gt; &lt;managed-bean&gt; &lt;managed-bean-name&gt;contactCtrl&lt;/managed-bean-name&gt; &lt;managed-bean-class&gt;clases.admContact&lt;/managed-bean-class&gt; &lt;managed-bean-scope&gt;session&lt;/managed-bean-scope&gt; &lt;/managed-bean&gt; La clase AlgunBean.java solo tendra sus propiedades y los respectivos metodos set y get La clase admContact debe implementar el metodo saveContact donde se realizan los algoritmos que cada quien requiera, pero ya se puede sacar de la session en bean registrado como contact con los datos que ingreso el usuario. Tambien elimine la etiqueta &lt;f:loadBundle basename="MessageResources" var="msg"/&gt; y remplace su referencia en el boton de esta manera: &lt;h:commandButton id="button" action="#{contactCtrl.saveContact}" value="Enviar" /&gt; Con eso les tiene que funcionar, y bueno pese a esos pequeñas correcciones estaba bueno el tutorial

Fecha publicación: 2009-09-04-11:26:04

Autor:

[Juan Carlos] Tampoco tiene el recurso para los mensajes...

Fecha publicación: 2009-09-04-11:05:51

Autor:

[Juan Carlos] El tar.gz que contiene las fuentes del proyecto no contiene el archivo web.xml