icono LinkedIn
Iván García Puebla

Consultor tecnológico de desarrollo de proyectos informáticos.

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2008-01-16

Tutorial visitado 90.863 veces Descargar en PDF
Ejemplo de aplicacion web con Java Server Faces (JSF), ICEfaces, Eclipse Europa y Tomcat paso a paso

Ejemplo de web con ICEfaces

 

En Autentia nos gusta aprender y trabajar con las últimas tecnologías, y en este tutorial os presentamos un ejemplo  sencillo pero práctico de ICEfaces con JSF. Es recomendable que lo sigas paso a paso, no te importe el tiempo que dediques (según el nivel inicial que tengas). Seguro que aprenderás cosas nuevas, y sobre todo, te divertirás al ver los resultados. ¡Comencemos!

Introducción

 

La combinación JEE-Ajax están en constante evolución,  y en este tutorial vamos a ver un ejemplo paso a paso de cómo sacar partido a ambas cosas usando Icefaces 1.6. ICEfaces es un proyecto open source de ICESoft Tecnologies que ofrece medio centenar de componentes JSF, Ajax basado en servidor,  y sus fundamentos  lo sitúan como un framework muy a tener en cuenta para nuestros desarrollos en Java con características visuales avanzadas:

·        El uso de Ajax es transparente para el programador. Introducir los componentes disponibles en nuestro código cliente y listo!

·        Compatibilidad 100% con los estándares Java.

·        De todos los frameworks Ajax del mercado, ICEfaces destaca especialmente por su seguridad y compatibilidad con servidores de aplicaciones Java, IDEs, componentes de terceros y librerías de javascript.

 

En el tutorial http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=tomcat6_icefaces podrás encontrar información ampliada, así como en la página del proyecto  www.icefaces.org.

 

Manos a la obra.

 

Partiremos del siguiente entorno:

·        Distribución de binarios de ICEfaces 1.6.2 (sección de descargas de icecafes.org).

·        Apache ant  1.7.0

·        Apache Tomcat 5.5

·        Un IDE, como por ejemplo, Eclipse 3.3. ICEfaces.org  ofrece un plugin para Eclipse y un buen consejo es instalarlo si se quiere profundizar con ICEfaces. Para nuestra aplicación no es necesario un IDE, pero nos facilita la codificación, depuración y control de dependencias.

 

El ejercicio práctico consiste en una página web que permita realizar búsquedas en un catálogo, y dar altas al mismo. En sí no parece nada innovador, pero veremos cómo ICEfaces va a dar mucho juego con poco código :-) La temática será la astronomía y el catálogo será de estrellas, si bien puedes adaptarlo a tus gustos casi de manera inmediata.

 

Comenzamos dando de alta un proyecto Java en Eclipse, TutorialIcefaces, y creamos la siguiente estructura de directorios:

 

Estructura de un proyecto web en Eclipse

 

src y la JRE la proporciona el propio eclipse. A nivel raíz del proyecto creamos lib y web. Como carpetas hijas de web, img, META-INF y WEB-INF. Y dentro de WEB-INF, resources.

 

Creamos el web.xml bajo WEB-INF con la configuración del proyecto para integrar ICEfaces, mapear los servlets, etc.

<?xml version="1.0"?>

 

<!DOCTYPE web-app PUBLIC

  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

  "http://java.sun.com/dtd/web-app_2_3.dtd">

 

<web-app>

 

    <context-param>

        <param-name>com.icesoft.faces.debugDOMUpdate</param-name>

        <param-value>false</param-value>

    </context-param>

 

    <context-param>

        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>

        <param-value>server</param-value>

        <description>

            State saving method: "client" or "server" (= default)

            See JSF Specification 2.5.2

        </description>

    </context-param>

   

    <context-param>

        <param-name>com.icesoft.faces.concurrentDOMViews</param-name>

        <param-value>true</param-value>

    </context-param>

   

    <context-param>

        <param-name>com.icesoft.faces.synchronousUpdate</param-name>

        <param-value>true</param-value>

    </context-param>

     

    <!-- Faces Servlet -->

    <servlet>

        <servlet-name>Faces Servlet</servlet-name>

        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

 

    <servlet>

        <servlet-name>Persistent Faces Servlet</servlet-name>

        <servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class>

        <load-on-startup> 1 </load-on-startup>

    </servlet>

 

    <servlet>

        <servlet-name>Blocking Servlet</servlet-name>

        <servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class>

        <load-on-startup> 1 </load-on-startup>

    </servlet>

 

    <!-- extension mapping -->

    <servlet-mapping>

        <servlet-name>Faces Servlet</servlet-name>

        <url-pattern>*.jsf</url-pattern>

    </servlet-mapping>

 

    <servlet-mapping>

        <servlet-name>Persistent Faces Servlet</servlet-name>

        <url-pattern>*.jsf</url-pattern>

    </servlet-mapping>

 

    <servlet-mapping>

        <servlet-name>Persistent Faces Servlet</servlet-name>

        <url-pattern>*.iface</url-pattern>

    </servlet-mapping>

 

    <servlet-mapping>

        <servlet-name>Persistent Faces Servlet</servlet-name>

        <url-pattern>/xmlhttp/*</url-pattern>

    </servlet-mapping>

 

    <servlet-mapping>

        <servlet-name>Blocking Servlet</servlet-name>

        <url-pattern>/block/*</url-pattern>

    </servlet-mapping>

 

    <session-config>

      <session-timeout>1</session-timeout>

    </session-config>

   

    <!-- Welcome files -->

    <welcome-file-list>

        <welcome-file>index.jsf</welcome-file>

        <welcome-file>index.jsp</welcome-file>

        <welcome-file>index.html</welcome-file>

    </welcome-file-list>

 

</web-app>

 

También en WEB-INF creamos el fichero faces-config.xml. Partimos del código que se muestra a continuación y lo iremos completando posteriormente.

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

 

 

<!DOCTYPE faces-config PUBLIC

  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"

  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

 

<!-- =========== FULL CONFIGURATION FILE ================================== -->

 

<faces-config xmlns="http://java.sun.com/JSF/Configuration">

  <application>

    <locale-config>

      <default-locale>en_US</default-locale>

    </locale-config>

  </application>

     

</faces-config>

 

 

Ahora entramos en la capa vista de nuestra aplicación. Creamos un welcome file, digamos, WEB-INF/index.jsp que vaya a la página del web que nos interese:

 

<html>

    <head>

        <title>Star Catalogue - AUTENTIA</title>

    </head>

    <body>

        <jsp:forward page="/starcatalogue.iface"/>

    </body>

</html>

 

Creamos el fichero apuntado: starcatalogue.jspx. Tendrá como contenido el código HTML bien formado junto con los componentes de JSF e ICEfaces.

 

Vamos a implementar la primera funcionalidad de la web, el buscador predictivo de estrellas del catálogo.  Queremos que cuando empecemos a escribir texto, se muestren automáticamente los resultados más cercanos. Así, cuando el nombre de la estrella buscada esté a nuestra vista podemos hacer click con el ratón sobre su nombre y mostrar la información del astro.

 

Consultamos el TAG list de los componentes que ofrece ICEfaces (ver documentación online o en la distribución descargada en nuestro ordenador, e.g. ICEfaces-1.6.2-bin/icefaces/docs/tld/index.html) y encontramos las que mejor nos sirvan:

 

·        ice:outputText para mostrar texto al usuario.

·        Ice:form para crear el formulario.

·        ice:selectInputText para implementar un cuadro de búsqueda preditivo.

·        ice:graphicImage para mostrar una imagen (e.g. banner, cabecera, etc.).

·        ice:panelGroup para agrupar componentes.

·        ice:panelGrid para que el formulario y el texto de los componentes respectivos se muestren en la página ordenados (en realidad equivale al uso de capas o tablas en HTML tradicional para configurar el layout de la interfaz).

 

Hemos diseñado la interfaz con este aspecto:

 

Interfaz de la web con JSF (Java Server Faces) y ICEFaces

 

Por lo que lo implementamos en catalogue.jspx así:

<f:view xmlns:f="http://java.sun.com/jsf/core"

        xmlns:h="http://java.sun.com/jsf/html"

        xmlns:ice="http://www.icesoft.com/icefaces/component">

<html>

    <head>

        <title>Star Catalogue</title>

        <link href="./xmlhttp/css/xp/xp.css" rel="stylesheet" type="text/css"/>

    </head>

    <body>

    <p style="width:800px;">

    <ice:graphicImage url="img/header.jpg" style="border:none;"/>

    <br/><br/>

       Use this page to find out information of some of the brightest stars in the northern hemisphere.

       Contributing to the catalog is easy - just fill in the form below!</p>

       <br/>     

      

      

       <!-- Our predictive search form begins here -->

        <ice:form style="width:800px;">

            <fieldset>

            <legend><b>Search the catalogue</b></legend>

            <ice:panelGrid columns="1">

           

                <!-- input box + list of partial results -->

                <ice:panelGroup>

                    <ice:outputText value="Enter the name of the star to show its details:"/><br/><br/>

                    <ice:selectInputText rows="7" width="350" valueChangeListener="#{autoCompleteCatalogBean.updateStarList}">

                        <f:selectItems value="#{autoCompleteCatalogBean.list}"/>

                    </ice:selectInputText>

                </ice:panelGroup>

                <br/>

               

                <!-- text information of the selected star data -->

                <ice:panelGroup>

                    <ice:outputText value="Data found:" style="font-weight:bold;"/>

                    <ice:panelGrid columns="2">

                        <ice:outputText value="Name:"/>

                        <ice:outputText id="name"

                                        value="#{autoCompleteCatalogBean.currentStar.name}"/>

                        <ice:outputText value="Magnitude:"/>

                        <ice:outputText id="magnitude"

                                        value="#{autoCompleteCatalogBean.currentStar.magnitude}"/>

                        <ice:outputText value="Constellation:"/>

                        <ice:outputText id="constellation"

                                        value="#{autoCompleteCatalogBean.currentStar.constellation}"/>

                        <ice:outputText value="Brief description:"/>

                        <ice:outputText id="description"

                                        value="#{autoCompleteCatalogBean.currentStar.briefDescription}"/>

                    </ice:panelGrid>

                </ice:panelGroup>

               

            </ice:panelGrid>

            </fieldset>

        </ice:form>

       

        <!--  End of predictive search form -->

       

        <br/>

 

 

    </body>

</html>

</f:view>

 

 

Puede apreciarse en el código que hemos introducido invocaciones a atributos de javabeans. Nuestro código implementará la lógica necesaria para actualizarlos y para responder a los eventos generados en clientes y atendidos en servidor. Es el caso del atributo valueChangeListener, que invoca el método listener updateStarList de autoCompleteCatalogBean. Los nombres de los beans son un mapeo con ficheros de código reales, con igual o distinto nombre.

 

Implementación de los beans

 

La lógica de la aplicación la crearemos en la carpeta de fuentes del proyeto, src bajo paquetes:

 

·        com.autentia.starcatalogue: creamos las clases StarBean.java que modelará una entidad de tipo estrella, y SkyData.java con datos que necesitaremos.

 

package com.autentia.starcatalogue;

 

/**

 *

 * Simple Star entity definition for database information

 *

 * @author AUTENTIA www.autentia.com Ivan Garcia Puebla

 * @version 1.0

 *

 */

public class StarBean {

 

      // attributes

      private String name;

      private String magnitude;

      private String constellation;

      private String briefDescription;

     

 

      /**

       *

       * Constructor with full data provided

       *

       * @param name Star name

       * @param magnitude Apparent magnitude

       * @param constellation Parent constellation

       * @param briefDescription A few words

       */

      public StarBean(String name, String magnitude, String constellation,

                  String briefDescription) {

            this.name = name;

            this.magnitude = magnitude;

            this.constellation = constellation;

            this.briefDescription = briefDescription;

      }

     

     

      /**

       * Default constructor

       */

      public StarBean()

      {

           

      }

 

      /**

       * @return the name

       */

      public String getName() {

            return name;

      }

 

      /**

       * @param name

       *            the name to set

       */

      public void setName(String name) {

            this.name = name;

      }

 

      /**

       * @return the magnitude

       */

      public String getMagnitude() {

            return magnitude;

      }

 

      /**

       * @param magnitude

       *            the magnitude to set

       */

      public void setMagnitude(String magnitude) {

            this.magnitude = magnitude;

      }

 

      /**

       * @return the constellation

       */

      public String getConstellation() {

            return constellation;

      }

 

      /**

       * @param constellation

       *            the constellation to set

       */

      public void setConstellation(String constellation) {

            this.constellation = constellation;

      }

 

      /**

       * @return the briefDescription

       */

      public String getBriefDescription() {

            return briefDescription;

      }

 

      /**

       * @param briefDescription

       *            the briefDescription to set

       */

      public void setBriefDescription(String briefDescription) {

            this.briefDescription = briefDescription;

      }

 

}

 

 

package com.autentia.starcatalogue;

 

import java.util.ArrayList;

import java.util.List;

import javax.faces.model.SelectItem;

 

/**

 *

 * Generic sky data

 *

 * @author AUTENTIA www.autentia.com Ivan Garcia Puebla

 * @version 1.0

 *

 */

public class SkyDataBean {

 

      // Just a logical division of a hemisphere

 

      public static final String CIRCUMPOLAR_REGION = "Circumpolar";

      public static final String ZODIAC_REGION = "Zodiac";

      public static final String OTHER_REGION = "Other";

      public static final String[] regions = { CIRCUMPOLAR_REGION, ZODIAC_REGION,

                  OTHER_REGION };

 

      // just a few constellation names grouped by the sky region they belong to

      public static final String[] circumpolarConstellations = { "Ursa Major",

                  "Ursa Minor", "Cassiopeia", "Perseus", "Draco" };

      public static final String[] zodiacConstellations = { "Aries", "Gemini",

                  "Leo", "Virgo", "Scorpius", "Aquarius", "Taurus", "Pisces" };

      public static final String[] otherRegionConstellations = { "Hercules",

                  "Orion", "Lacerta", "Ophiuchus", "Serpens", "Pegasus", "Lynx",

                  "Cygnus", "Cetus", "Andromeda", "Lyra" };

     

     

      /**

       * Interesting areas of the sky

       *

       * @return Item list of Interesting areas of the sky

       */

      public List getRegions() {

            List regionsList = new ArrayList(regions.length);

 

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

                  regionsList.add(new SelectItem(regions[i], regions[i]));

 

            return regionsList;

      }

 

}

 

Las dependencias para usar ICEfaces en nuestro proyecto, que debemos copiar en el lib del proyecto e integrar en el classpath de Eclipse son:

 

o   jsf-api.jar

o   jsf-impl.jar

o   servlet-api.jar

o   backport-util-concurrent.jar

o   commons-beanutils.jar

o   commons-collections.jar

o   commons-discovery.jar

o   commons-digester.jar

o   commons-fileupload.jar

o   commons-logging.jar

o   commons-logging-api.jar

o   el-api.jar

o   icefaces.jar

o    icefaces-comps.jar

o    xercesImpl.jar

o   xml-apis.jar

 

·        com.autentia.starcatalogue.search: AutoCompleteCatalogDictionary.java. Partiremos de uno de los ejemplos de la documentación de ICEfaces (autocompletado) y lo modificaremos. Esta clase cargará el catálogo de estrellas de disco y mantendrá disponible en el ámbito de la aplicación. También crearemos AutoCompleteCatalogBean.java que responderá a eventos de la interfaz.

 

/*

 * [...]

 * The Original Code is ICEfaces 1.5 open source software code, released

 * November 5, 2006. The Initial Developer of the Original Code is ICEsoft

 * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)

 * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.

 * [..p]

 */

 

 

package com.autentia.starcatalogue.search;

 

import com.autentia.starcatalogue.StarBean;

import com.icesoft.faces.component.selectinputtext.SelectInputText;

 

import javax.faces.event.ValueChangeEvent;

import javax.faces.model.SelectItem;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Iterator;

import java.util.List;

 

/**

 * Stores the values picked from the AutoCompleteCatalogDictionary (different scope to

 * avoid memory hole).

 *

 * CHANGELOG [02/01/2007]: modified for getting support to Star entities

 * CHANGELOG [03/01/2007]: introduced dictionary management improvements

 *

 * @see AutoCompleteCatalogueDictionary

 * @author The Original Code is ICEfaces 1.5 open source software code. Modified by Ivan Garcia Puebla – AUTENTIA www.autentia.com

 * @version 2.1

 */

public class AutoCompleteCatalogBean {

 

 

      // list of stars, used for auto complete list.

      private static List dictionary;

 

      // default star, no value.

      private StarBean currentStar = new StarBean("", "", "", "");

 

      // list of possible matches.

      private List matchesList = new ArrayList();

 

      /**

       * Called when a user has modifed the SelectInputText value. This method

       * call causes the match list to be updated.

       *

       * @param event

       */

      public void updateStarList(ValueChangeEvent event) {

 

            // get a new list of matches.

            setMatches(event);

 

            // Get the auto complete component from the event and assing

            if (event.getComponent() instanceof SelectInputText) {

                  SelectInputText autoComplete = (SelectInputText) event

                              .getComponent();

                  // if no selected item then return the previously selected item.

                  if (autoComplete.getSelectedItem() != null) {

                        currentStar = (StarBean) autoComplete.getSelectedItem().getValue();

                  }

                  // otherwise if there is a selected item get the value from the

                  // match list

                  else {

                        StarBean tempStar = getMatch(autoComplete.getValue().toString());

                        if (tempStar != null) {

                             currentStar = tempStar;

                        }

                  }

            }

      }

 

      /**

       * Gets the currently selected star.

       *

       * @return selected star.

       */

      public StarBean getCurrentStar() {

            return currentStar;

      }

 

      /**

       * The list of possible matches for the given SelectInputText value

       *

       * @return list of possible matches.

       */

      public List getList() {

            return matchesList;

      }

 

      private StarBean getMatch(String value) {

            StarBean result = null;

            if (matchesList != null) {

                  SelectItem si;

                  Iterator iter = matchesList.iterator();

                  while (iter.hasNext()) {

                        si = (SelectItem) iter.next();

                        if (value.equals(si.getLabel())) {

                             result = (StarBean) si.getValue();

                        }

                  }

            }

            return result;

      }

 

      public List getDictionary() {

            return dictionary;

      }

 

      public void setDictionary(List dictionary) {

            AutoCompleteCatalogBean.dictionary = dictionary;

      }

     

      /**

       * Refresh the dictionary on the fly in case of showing the changes

       * @param dictionary

       */

      public static void refreshDictionary(List dictionary)

      {

            AutoCompleteCatalogBean.dictionary = dictionary;

      }

 

      /**

       * Utility method for building the match list given the current value of the

       * SelectInputText component.

       *

       * @param event

       */

      private void setMatches(ValueChangeEvent event) {

 

            Object searchWord = event.getNewValue();

            int maxMatches = ((SelectInputText) event.getComponent()).getRows();

            List matchList = new ArrayList(maxMatches);

 

            try {

 

                  int insert = Collections.binarySearch(dictionary, searchWord,

                             AutoCompleteCatalogDictionary.LABEL_COMPARATOR);

 

                  // less then zero if wer have a partial match

                  if (insert < 0) {

                        insert = Math.abs(insert) - 1;

                  }

 

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

                        // quit the match list creation if the index is larger then

                        // max entries in the dictionary if we have added maxMatches.

                        if ((insert + i) >= dictionary.size() || i >= maxMatches) {

                             break;

                        }

                        matchList.add(dictionary.get(insert + i));

                  }

            } catch (Throwable e) {

                  e.printStackTrace();

            }

            // assign new matchList

            if (this.matchesList != null) {

                  this.matchesList.clear();

                  this.matchesList = null;

            }

            this.matchesList = matchList;

      }

}

 

/*

 * [...]

 * The Original Code is ICEfaces 1.5 open source software code, released

 * November 5, 2006. The Initial Developer of the Original Code is ICEsoft

 * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)

 * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.

 * [..p]

 */

 

package com.autentia.starcatalogue.search;

 

 

import com.autentia.starcatalogue.StarBean;

 

import javax.faces.context.FacesContext;

import javax.faces.model.SelectItem;

import javax.servlet.http.HttpSession;

import java.beans.XMLDecoder;

import java.io.BufferedInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

import java.util.List;

import java.util.ListIterator;

 

 

/**

 *

 *

 *

 * Application-scope bean used to store static lookup information for

 * AutoComplete (selectInputText) example. Statically referenced by

 * AutoCompleteCatalogBean as the dictionary is rather large.

 *

 * CHANGELOG [02/01/2007]: modified for getting support to Star entities

 * CHANGELOG [03/01/2007]: introduced dictionary management improvements

 *

 * @see AutoCompleteCatalogBean

 * @author The Original Code is ICEfaces 1.5 open source software code. Modified by Ivan Garcia Puebla – AUTENTIA www.autentia.com

 * @version 2.4

 */

public class AutoCompleteCatalogDictionary {

 

 

      // list of cities.

      private static List dictionary;

 

      public AutoCompleteCatalogDictionary() {

            // initialize the ditionary

            try {

                  init();

            } catch (Exception e) {

                  e.printStackTrace();

            }

      }

 

 

      /**

       * Comparator utility for sorting star names.

       */

      public static final Comparator LABEL_COMPARATOR = new Comparator() {

            String s1;

            String s2;

 

            // compare method for star entries.

            public int compare(Object o1, Object o2) {

 

                  if (o1 instanceof SelectItem) {

                        s1 = ((SelectItem) o1).getLabel();

                  } else {

                        s1 = o1.toString();

                  }

 

                  if (o2 instanceof SelectItem) {

                        s2 = ((SelectItem) o2).getLabel();

                  } else {

                        s2 = o2.toString();

                  }

                  // compare ingnoring case, give the user a more automated feel when

                  // typing

                  return s1.compareToIgnoreCase(s2);

            }

      };

 

      /**

       * Gets the dictionary of cities.

       *

       * @return dictionary list in sorted by star name, ascending.

       */

      public List getDictionary() {

            return dictionary;

      }

     

     

     

      /**

       * Converts the catalogue to a Star objects list

       *

       */

      private synchronized static void convertDictionary()

      {

            ArrayList tmpCatalogue=new ArrayList(dictionary.size());

            for(ListIterator it=dictionary.listIterator();it.hasNext();)

            {

                  SelectItem item=(SelectItem) it.next();

                  tmpCatalogue.add((StarBean) item.getValue());

            }

            dictionary=tmpCatalogue;

            tmpCatalogue=null;

      }

     

     

     

      /**

       * Loads the dictionary into memory

       *

       */

      private synchronized static void loadDictionary()

      {

            // Raw list of stars

            List starList = null;

            // load the star dictionary from the xml file.

 

            // get the path of the file

            HttpSession session = (HttpSession) FacesContext.getCurrentInstance()

                        .getExternalContext().getSession(true);

            String basePath = session.getServletContext().getRealPath(

                        "/WEB-INF/resources");

            basePath += "/starcatalogue.xml";

 

            // read the file

            File catalogFile;

            FileInputStream catalogFileStream;

            try {

                  catalogFile = new File(basePath);

                  catalogFileStream=new FileInputStream(catalogFile);

            } catch (Exception e) {

                  e.printStackTrace();

                  return;

            }

 

            // get the xml stream and decode it.

            if (catalogFile != null) {

                  try {

                        BufferedInputStream dictionaryStream = new BufferedInputStream(

                                   catalogFileStream);

                        XMLDecoder xDecoder = new XMLDecoder(dictionaryStream);

                        // get the city list.

                        starList = (List) xDecoder.readObject();

                        dictionaryStream.close();

                        catalogFileStream.close();

                        xDecoder.close();

                  } catch (ArrayIndexOutOfBoundsException e) {

                        e.printStackTrace();

                        return;

                  } catch (IOException e) {

                        e.printStackTrace();

                        return;

                  }

            }

 

            // Finally load the object from the xml file.

            if (starList != null) {

                  dictionary = new ArrayList(starList.size());

                  StarBean tmpStar;

                  for (int i = 0, max = starList.size(); i < max; i++) {

                        tmpStar = (StarBean) starList.get(i);

                        if (tmpStar != null && tmpStar.getName() != null) {

                             dictionary.add(new SelectItem(tmpStar, tmpStar.getName()));

                        }

                  }

                  starList.clear();

                  // finally sort the list

                  Collections.sort(dictionary, LABEL_COMPARATOR);

            }

      }

     

     

      private static void init() {

            loadDictionary();

      }

}

 

Completamos el fichero faces-config con los nuevos beans definidos para que puedan ser resueltos desde la vista:

 

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

 

 

<!DOCTYPE faces-config PUBLIC

  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"

  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

 

<!-- =========== FULL CONFIGURATION FILE ================================== -->

 

<faces-config xmlns="http://java.sun.com/JSF/Configuration">

  <application>

    <locale-config>

      <default-locale>en_US</default-locale>

    </locale-config>

  </application>

   

  <!--  Search engine mappings-->

  <managed-bean>

    <managed-bean-name>autoCompleteCatalogDictionary</managed-bean-name>

    <managed-bean-class>

            com.autentia.starcatalogue.search.AutoCompleteCatalogDictionary

        </managed-bean-class>

    <managed-bean-scope>application</managed-bean-scope>

  </managed-bean>

  <managed-bean>

    <managed-bean-name>autoCompleteCatalogBean</managed-bean-name>

    <managed-bean-class>

            com.autentia.starcatalogue.search.AutoCompleteCatalogBean

        </managed-bean-class>

    <managed-bean-scope>request</managed-bean-scope>

    <managed-property>

      <property-name>dictionary</property-name>

      <value>#{autoCompleteCatalogDictionary.dictionary}</value>

    </managed-property>

  </managed-bean>

   

</faces-config>

 

 

En el directorio WEB-INF/resources/starcatalogue.xml se almacenará la instancia persistente del catálogo estelar. Lo crearemos con un contenido inicial con propósitos de prueba:

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

<java version="1.5.0_14" class="java.beans.XMLDecoder">

 <object class="java.util.ArrayList">

  <void method="add">

   <object class="com.autentia.starcatalogue.StarBean">

    <void property="briefDescription">

     <string>The 4th brightest star in the northern hemisphere</string>

    </void>

    <void property="constellation">

     <string>Bootes</string>

    </void>

    <void property="magnitude">

     <string>-0.1</string>

    </void>

    <void property="name">

     <string>Arcturus</string>

    </void>

   </object>

  </void>

  <void method="add">

   <object class="com.autentia.starcatalogue.StarBean">

    <void property="briefDescription">

     <string>Binary star with an orbital period og 470 years</string>

    </void>

    <void property="constellation">

     <string>Gemini</string>

    </void>

    <void property="magnitude">

     <string>1.9</string>

    </void>

    <void property="name">

     <string>Castor</string>

    </void>

   </object>

  </void>

  <void method="add">

   <object class="com.autentia.starcatalogue.StarBean">

    <void property="briefDescription">

     <string>Alpha Cygnus, 3000 light-years far away from the Earth</string>

    </void>

    <void property="constellation">

     <string>Cygnus</string>

    </void>

    <void property="magnitude">

     <string>1.3</string>

    </void>

    <void property="name">

     <string>Deneb</string>

    </void>

   </object>

  </void>

 </object>

</java>

 

Vamos a ver los primeros resultados. Creamos un script ant a nivel raiz de proyecto : build.xml.

<project name="starcatalogue" default="build.war">

 

<property name="build.sysclasspath" value="ignore"/>

 

<property name="build.dir" location="build"/>

<property name="dist.dir" location="dist"/>

<property name="src.dir" location="src"/>

<property name="web.content.dir" location="web"/>

<property name="web.inf.dir" location="${web.content.dir}/WEB-INF"/>

<property name="classes.dir" location="${web.inf.dir}/classes"/>

<property name="app.lib.dir" location="${web.inf.dir}/lib"/>

<property name="autentiaApp.lib.dir" location="lib"/>

           

<property name="compile.source" value="1.4"/>

<property name="compile.target" value="1.4"/>

<property name="compile.debug" value="true"/>

 

     

 

<macrodef name="clean">

    <sequential>

        <delete includeemptydirs="true" quiet="true">

            <fileset dir="${build.dir}"/>

            <fileset dir="${dist.dir}"/>

            <fileset dir="${classes.dir}" includes="**/*"/>

            <fileset dir="${app.lib.dir}" includes="*.jar"/>

        </delete>

    </sequential>

</macrodef>

 

           

           

<macrodef name="compile">

    <attribute name="src.copy.excludes" default=""/>

    <element name="add.javac.elements" optional="true"/>

 

    <sequential>

        <mkdir dir="${src.dir}"/>

        <mkdir dir="${classes.dir}"/>

        <mkdir dir="${app.lib.dir}"/>

 

        <javac destdir="${classes.dir}"

            sourcepath=""

            source="${compile.source}"

            target="${compile.target}"

            debug="${compile.debug}">

           

            <src location="${src.dir}"/>

            <include name="**/*.java"/>

            <classpath>

                <fileset dir="${autentiaApp.lib.dir}" includes="*.jar"/>

            </classpath>

            <add.javac.elements/>

        </javac>

 

        <copy todir="${classes.dir}" preservelastmodified="true">

            <fileset dir="${src.dir}" excludes="@{src.copy.excludes}"/>

        </copy>

    </sequential>

</macrodef>

 

     

     

<macrodef name="build.war">

    <attribute name="war.file.name" default="${ant.project.name}.war"/>

    <element name="add.filesets" optional="true"/>

 

    <sequential>

        <mkdir dir="${dist.dir}"/>

 

        <copy todir="${app.lib.dir}" preservelastmodified="true">

            <fileset dir="${autentiaApp.lib.dir}" includes="*.jar" excludes="servlet-api.jar"/>

        </copy>

 

        <war basedir="${web.content.dir}" destfile="${dist.dir}/@{war.file.name}" duplicate="fail"

             webxml="${web.inf.dir}/web.xml" excludes="WEB-INF/web.xml">

            <add.filesets/>

        </war>

    </sequential>

</macrodef>

 

     

     

     

<target name="clean">

    <clean/>

</target>

 

<target name="compile">

    <compile/>

</target>

 

<target name="build.war" depends="compile">

    <build.war/>

</target>

 

 

</project>

 

En este punto, la situación actual del proyecto en eclipse es la siguiente:

 

Estructura del proyecto de la web con JSF (Java Server Faces) y ICEFaces en Eclipse Europa

 

Desde consola y en el directorio del proyecto ejecutamos ant build.war, copiamos el starcatalogue.war (generado en dist) en la carpeta webapps del Tomcat y levantamos el servidor. Accedemos a la aplicación (e.g. http://localhost:8080/starcatalogue) y veremos algo como lo siguiente:

 

Buscador con autocompletado sensible al contexto utilizando ICEFaces

Buscador con un valor de la lista presentada por el componente de ICEFaces

 

Ampliando el catálogo

Vamos a añadir la segunda funcionalidad a nuestra web: la de poder añadir estrellas a nuestro catálogo.  Para una nueva estrella debemos introducir (de manera obligatoria, si no no se efectúa la acción) su nombre, el de la constelación que la alberga, la magnitud de su brillo y una breve descripción.  

Vamos a hacer una clasificación de las constelaciones: si son circumpolares, zodiacales, o de otra zona. En función de la zona seleccionada en un combo, la lista de constelaciones seleccionables en un segundo combo son diferentes.

Finalmente confirmamos la operación con un mensaje de texo.

Usaremos el componente ice:selectOneListBox para mostrar un HTML select junto con el atributo partialSubmit. Esto es importante para hacer uso de Ajax: cuando se modifica este combo, se realiza una request inmediata al servidor invocando al listener definido en el atributo valueChangeListener; este listener filtrará las constelaciones de esa zona.

A starcatalogue.jspx añadimos, antes del </body>:

  <!-- Star insertion form  -->

        <ice:form style="width:800px;">

            <fieldset>

            <legend><b>Add your favourite star</b></legend>

            <ice:panelGroup>

              <ice:panelGrid columns="2">

                    <ice:outputText value="1. Select the sky region of the new star:"/>

                    <ice:selectOneListbox size="1" valueChangeListener="#{contributionBean.filterRegion}" partialSubmit="true">

                      <f:selectItems value="#{skyData.regions}"/>

                    </ice:selectOneListbox>

                    <ice:outputText value="2. Select the belonging constellation:"/>

                    <ice:selectOneListbox size="1" value="#{contributionBean.starConstellation}">

                      <f:selectItems value="#{contributionBean.currentConstellations}"/>

                    </ice:selectOneListbox>   

                    <ice:outputText value="3. Insert star details:"/>

                    <ice:panelGrid columns="2">

                      <ice:outputText value="Name: "/>

                      <ice:inputText size="30" required="true" value="#{contributionBean.starName}"/>

                      <ice:outputText value="Magnitude: "/>

                      <ice:inputText size="5" required="true" value="#{contributionBean.starMagnitude}"/>

                      <ice:outputText value="Description: "/>

                      <ice:inputText size="60" required="true" value="#{contributionBean.starBriefDescription}"/>

                    </ice:panelGrid>

                    <ice:outputText value="4. Add it:"/>

                    <ice:commandButton actionListener="#{contributionBean.sumbitNewStar}" value="Add!" />

                    <ice:outputText value=""/>

                    <ice:outputText value="#{contributionBean.submitMessage}"/> <!--  inform the result of the submit! -->

               </ice:panelGrid>   

             </ice:panelGroup>  

            </fieldset>

        </ice:form>

 

Creamos el listener ContributionBean.java bajo un paquete com.autentia.starcatalogue.contribution:

package com.autentia.starcatalogue.contribution;

 

import java.util.ArrayList;

import java.util.List;

 

import javax.faces.event.ActionEvent;

import javax.faces.event.ValueChangeEvent;

import javax.faces.model.SelectItem;

 

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

 

import com.autentia.starcatalogue.SkyDataBean;

import com.autentia.starcatalogue.StarBean;

import com.autentia.starcatalogue.search.AutoCompleteCatalogDictionary;

import com.icesoft.faces.component.ext.HtmlSelectOneListbox;

 

/**

 *

 * Controller for the contribution functionality of the site

 *

 * @author AUTENTIA www.autentia.com - Ivan Garcia Puebla

 * @version 1.0

 */

public class ContributionBean extends SkyDataBean {

 

      private static Log log = LogFactory.getLog(ContributionBean.class);

     

      private List constellationList;

      private String submitMessage;

      private String starConstellation;

      private String starName;

      private String starMagnitude;

      private String starBriefDescription;

 

      public ContributionBean() {

            constellationList = new ArrayList();

            submitMessage = "";

            starConstellation = "";

            starName = "";

            starMagnitude = "";

            starBriefDescription = "";

      }

 

      // EVENT METHODS *****************************************************

 

      /**

       * Called when a user has modifed the sky region selection list

       *

       * @param event

       *            Event fired

       */

      public void filterRegion(ValueChangeEvent event) {

 

            if (event.getComponent() instanceof HtmlSelectOneListbox) {

                  HtmlSelectOneListbox selection = (HtmlSelectOneListbox) event

                             .getComponent();

                  updateConstellationList(selection.getValue().toString());

            }

 

      }

 

      /**

       * Retrieves the form with the new star data

       *

       * @param event

       */

      public void sumbitNewStar(ActionEvent event) {

            // some validations may be done here...

 

            StarBean newStar = new StarBean(starName, starMagnitude, starConstellation,

                        starBriefDescription);

            AutoCompleteCatalogDictionary.addStar(newStar);

            submitMessage = starName+ " has been added to the catalogue. Thank you!";

      }

 

      /**

       * Fill in the constellation list according to their type

       *

       * @param type

       *            The type: circumpolar, zodiac, other, or null for all them

       */

      private void updateConstellationList(String type) {

 

            constellationList.clear();

 

            if (CIRCUMPOLAR_REGION.equals(type) || type == null)

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

                        constellationList.add(new SelectItem(

                                   circumpolarConstellations[i],

                                   circumpolarConstellations[i]));

 

            if (ZODIAC_REGION.equals(type) || type == null)

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

                        constellationList.add(new SelectItem(zodiacConstellations[i],

                                   zodiacConstellations[i]));

 

            if (OTHER_REGION.equals(type) || type == null)

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

                        constellationList.add(new SelectItem(

                                   otherRegionConstellations[i],

                                   otherRegionConstellations[i]));

      }

 

      // GETTERS & SETTERS **************************************************

 

      /**

       * Return the current constellation list

       *

       * @return The list belonging to the sky region selected

       */

      public List getCurrentConstellations() {

            return constellationList;

      }

 

      /**

       * @return the starConstellation

       */

      public String getStarConstellation() {

            return starConstellation;

      }

 

      /**

       * @param starConstellation

       *            the starConstellation to set

       */

      public void setStarConstellation(String starConstellation) {

            this.starConstellation = starConstellation;

      }

 

      /**

       * @return the starName

       */

      public String getStarName() {

            return starName;

      }

 

      /**

       * @param starName

       *            the starName to set

       */

      public void setStarName(String starName) {

            this.starName = starName;

      }

 

      /**

       * @return the starMagnitude

       */

      public String getStarMagnitude() {

            return starMagnitude;

      }

 

      /**

       * @param starMagnitude

       *            the starMagnitude to set

       */

      public void setStarMagnitude(String starMagnitude) {

            this.starMagnitude = starMagnitude;

      }

 

      /**

       * @return the starBriefDescription

       */

      public String getStarBriefDescription() {

            return starBriefDescription;

      }

 

      /**

       * @param starBriefDescription

       *            the starBriefDescription to set

       */

      public void setStarBriefDescription(String starBriefDescription) {

            this.starBriefDescription = starBriefDescription;

      }

 

      /**

       * @return the submitMessage

       */

      public String getSubmitMessage() {

            return submitMessage;

      }

 

      /**

       * @param submitMessage

       *            the submitMessage to set

       */

      public void setSubmitMessage(String submitMessage) {

            this.submitMessage = submitMessage;

      }

 

}

 

A la clase AutoCompleteCatalogBean.java le añadimos los métodos:

     /**

       * Add a star to the catalogue

       *

       * @param star Star to be added

       */

      public static void addStar(StarBean star)

      {

            convertDictionary(); // stantard stars objects!

            dictionary.add(star);

            saveDictionary();

            loadDictionary();

            AutoCompleteCatalogBean.refreshDictionary(dictionary);

      }

 

      /**

       * Makes the dictionady persistent

       *

       */

      private synchronized static void saveDictionary()

      {

            // save the star dictionary to the xml file

 

            // get the path of the file

            HttpSession session = (HttpSession) FacesContext.getCurrentInstance()

                        .getExternalContext().getSession(true);

            String basePath = session.getServletContext().getRealPath(

                        "/WEB-INF/resources");

            basePath += "/starcatalogue.xml";

           

           

 

            try {

                  FileOutputStream starCatalogFile = new FileOutputStream(basePath);

            XMLEncoder xEncoder = new XMLEncoder(starCatalogFile);

            xEncoder.writeObject(dictionary);

            xEncoder.close();

            starCatalogFile.close();

            } catch (FileNotFoundException e) {

                  e.printStackTrace();

                  return;

            } catch (IOException e) {

                  e.printStackTrace();

                  return;

            }          

           

      }

 

Finalmente completamos el descriptor faces-config.xml:

<!-- Adding stars to the catalogue - bean mappings --> 

  <managed-bean>

    <managed-bean-name>contributionBean</managed-bean-name>

    <managed-bean-class>

            com.autentia.starcatalogue.contribution.ContributionBean

        </managed-bean-class>

    <managed-bean-scope>request</managed-bean-scope>

  </managed-bean>

  <managed-bean>

    <managed-bean-name>skyData</managed-bean-name>

    <managed-bean-class>

            com.autentia.starcatalogue.SkyDataBean

    </managed-bean-class>

    <managed-bean-scope>application</managed-bean-scope>

  </managed-bean>

 

De nuevo construimos el war, desplegamos en Tomcat, y accedemos a la web. Obtendremos ahora:

Aspecto final de nuestra web dinamica con Ajax gracias a ICEFaces

Ya tenemos nuestra primera web con ICEfaces completa. Dependiendo de tus conocimientos previos habrás dedicado más o menos tiempo a realizarlo; pero lo importante es asomarse a la nueva tecnología y sacar tus propias conclusiones de cómo ello puede favorecerte en tus desarrollos.

 

En AUTENTIA compartimos nuestro conocimiento en últimas tecnologías, sobre las que profundizamos para aplicarlas en nuestro trabajo. Siempre puedes contactarnos en www.autentia.com para impartir cursos especializados, dar soporte, o aplicarlo directamente a los proyectos de tu empresa.

 

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-09-23-15:47:03

Autor: jorgevargasit

que no nos puedes pasar el war

Fecha publicación: 2011-06-01-18:13:39

Autor: hammery80

La verdad no entiendo muy bn este tutorial, tengo problemas con este componente ya que necesito el autocompletar con unos datos de una BD oracle, he leeido directamente desde la pagina de icefaces y no es muy diferente....si me pudieras ayudar a aclarar como hacer para llenar el autocomplete desde la BD te agradeceria.

Fecha publicación: 2010-09-16-23:00:36

Autor: Papablopo

"A la clase AutoCompleteCatalogBean.java le añadimos los métodos:" en esta parte hay un error, me parece que debe agregarse a la clase AutoCompleteCatalogDictionary, soy novato en esto del icefaces gracias por compartir el conocimiento

Fecha publicación: 2009-12-01-22:07:09

Autor: jcarmonaloeches

Gracias Iván por contestar a comentarios, se ve que eres una persona paciente y con vocación didáctica. En una tercera pasada, he vuelto a aprender conceptos nuevos, aportados en este tutorial ;)

Saludos!

Fecha publicación: 2009-11-10-15:37:01

Autor: Mario_Optimal

Si perdon la pantalla es esto es lo que me aparece ahora desde la consola y desde el ide anterior mente.
...
[javac] 26 errors

BUILD FAILED
/home/mario/workspace/TutorialIcefaces/build.xml:179: The following error occurred while executing this line:
/home/mario/workspace/TutorialIcefaces/build.xml:91: Compile failed; see the compiler error output for details.

Total time: 4 seconds

Fecha publicación: 2009-11-10-15:15:26

Autor: igpuebla

Mario, el comando que debes ejecutar es ant build.war (en tu comentario se ve que no está bien escrito, falta una 'd').

Fecha publicación: 2009-11-10-03:05:27

Autor: Mario_Optimal

Las barras "" no se porque se agregan cuando pego la pantalla

Fecha publicación: 2009-11-10-02:12:17

Autor: Mario_Optimal

Gracias por responder tan rapido la salida es asi

mario@mario-desktop:~/workspace/TutorialIcefaces$ ant buil.war

Buildfile: build.xml

BUILD FAILED
Target "buil.war" does not exist in the project "starcatalogue".

La verdad que estoy desorientado.

Fecha publicación: 2009-11-09-12:33:08

Autor: igpuebla

Mario, el target del ant es sobre build.war, y el la linea de comandos aparece "ant buil.war", comprueba la sintaxis.

Fecha publicación: 2009-11-09-05:37:30

Autor: Mario_Optimal

Buenas Iván
E realizado meticulosamente el tutorial y no tengo proble mas hasta que ejecuto ant build.war hay me aparece lo siguiente:
mario@mario-desktop:~/workspace/TutorialIcefaces$ ant buil.war
Buildfile: build.xml

BUILD FAILED
Target "buil.war" does not exist in the project "starcatalogue".

Total time: 0 seconds
Tendrias idea con tu experiencia cual seria el problema, lo e intentado desde el ide y tampoco e podido.
De antemano gracias por tu tiempo.-

Fecha publicación: 2009-11-01-19:06:43

Autor: igpuebla

Hola Jaime,

gracias por visitar de nuevo el tutorial y por tu crítica. Seguro que aportas esta idea porque ahora dominas más IceFaces y ves que este tutorial podría explicarse mejor. Y es cierto ;) También fue mi primera aplicación autodidacta con IceFaces y mi primer tutorial (y andaba algo perdido todo sea dicho) a si que ambas cosas son muy mejorables, pero por algo se empieza...

Saludos y gracias a tí

Fecha publicación: 2009-10-25-22:23:03

Autor: jcarmonaloeches

Hola Iván,

En una segunda pasada del tutorial, y con ánimo de crítica constructiva, creo que sería bueno que fueras más esquemático a la hora de desarrollar el tutorial. Existe demasiado código fuente y pantallazos y poca redacción. Desde mi punto de vista, te ánimo a que redactes más, explicando que vas realizando en cada paso.

Enhorabuena y gracias por la aportación.

Fecha publicación: 2009-08-27-03:48:27

Autor:

[Iván] Hola Emiliano, si nos das más datos podemos echarlo un vistazo y ayudarte. Un saludo.

Fecha publicación: 2009-08-26-09:05:20

Autor:

[Emiliano] Buenas, estoy siguiendo el ejemplo y tengo el siguiente error al acceder a la aplicación. "El recurso requerido (/starcatalogue/) no está disponible." donde puede estar el error?

Fecha publicación: 2009-05-15-03:02:49

Autor:

[Iván] Estupendo comentario Jaime, muchas gracias

Fecha publicación: 2009-04-30-12:39:24

Autor:

[Jaime Carmona Loeche] ¡Muy buen manual Iván! Un par de aportaciones de un humilde lector: Sería bueno indicar que debajo del directorio libr deben estar las librerías que se necesitan para compilar el proyecto, pues si no al intentar generar el war del ant no compila bien. Aporto el siguiente resumen con los ficheros implicados, y la implicación de cada uno de ellos en esta aplicación. (Nota de lector, siempre se agradece un pequeño esquema gráfico inicial, indicando las clases implicadas y el funcionamiento de cada uno de ellas, aunque si es el lector el que realiza esta tarea, siempre es más útil y didáctico). Esquema de ficheros. Ficheros de configuración. web.xml Especifica parámetros de contexto de ejecución. Define extensión mappings. Define los welcome files. faces-config.xml Define el lenguaje y los beans de sesión. Ficheros jsp. WEB-INF/index.jsp Redirige a starcatalogue.iface WEB-INF/catalogue.jspx Define un catálogo de búsqueda, utiliza librerías de JFaces, y comunica con autoCompleteCatalogBean (definido más adelante). Ficheros bean. StarBean.java Definición de la entidad estrella simple. SkyDataBean.java Datos genéricos del cielo. AutoCompleteCatalogueBean.java Almacena los valores pulsado desde el AutoCompleteCatalogDictionary, comunica con éste mediante una variable. AutoCompleteCatalogueDictionary.java Almacena todos los datos del catálogo, leyendo los valores desde un fichero xml. ContributionBean.java Extiende de SkyDataBean, y su utilidad es añadir nuevas estrellas. AutoCompleteCatalogBean.java Extiende de SkyDataBean, y su utilidad es añadir nuevas estrellas.

Fecha publicación: 2008-01-17-09:18:42

Autor:

[Raúl] Muy buen tutorial de icefaces en castellano!