5 Replies Latest reply on Nov 27, 2009 5:28 PM by jguglielmin

    non ascii characters urlencoded by simple get

    seamfrappe
      Greetings!
      My configuration is Seam 2.2.0.GA with IceFaces 1.8.2 on JBoss 5.1

      I'm working with non ascii characters and with a ice:form
      When I submit data by a partialSubmit, the dates and fields with non ascii characters behaves ok.

      BUT when I use a submit button things goes wrong and I get a URLEncoded value in my form fields.

      i.e.: 
             | If I enter  -> I got
             ------------------------------
             | Muñoz  ->  Mu%C3%B1oz
             -------------------------------
             | 12/12/1980 ->   12%2F12%2F1980
             --------------------------------


      I believe that this issue has relation with:
      http://seamframework.org/Community/WhyEntitypagexmlParameter
      and
      http://seamframework.org/Community/DateFormatErrorInPagexmlParamsASeamIssue

      If I use a converter with the Dates and the non ascii characters all works fine.
      I'm fighting against seam page.xml or components.xml, or other configuration to find a seam-friendly solution to this issue.

      Thank you.

      My Form and my converters are below:
      ----------------------------------------

      <ice:form id="pacienteSearch" styleClass="edit"  partialSubmit="true">        
                     <ice:panelGroup id="searchGroup" styleClass="formBorderHighlight">
                          <table width="100%" border="0" cellspacing="0" cellpadding="0">
                               <tr>
                                    <td class="iceDatTblColHdr2"><ice:outputText
                                         id="listPacienteId" value="B&#250;squeda simple" /></td>
                               </tr>
                          </table>
                          <ice:panelGroup id="listPanelGroupPacienteId" styleClass="edit">
                          Debes capturar todos los campos:
                          <hr />
                               <s:decorate id="sexodecId" template="layout/display.xhtml">
                                    <ui:define name="label">#{messages.genero}</ui:define>
                                    <ice:selectOneRadio id="logic"
                                         value="#{pacienteList.paciente.sexo}" partialSubmit="false"
                                         style="width: 225px;height: 12px; vertical-align:middle; display:inline"
                                         required="true">
                                         <f:selectItem itemLabel="#{messages.genero_femenino}" itemValue="FEMENINO" />
                                         <f:selectItem itemLabel="#{messages.genero_masculino}" itemValue="MASCULINO" />
                                    </ice:selectOneRadio>
                               </s:decorate>
                               <s:decorate id="apPaternodecId" template="layout/display.xhtml">
                                    <ui:define name="label">#{messages.apPaterno}</ui:define>
                                    <ice:inputText id="apPaterno"
                                         value="#{pacienteList.paciente.apPaterno}" partialSubmit="false"
                                         required="true"/>
                               </s:decorate>
                               <s:decorate id="nacimientodecId" template="layout/display.xhtml">
                                    <ui:define name="label">#{messages.fechaNacimiento}</ui:define>
                                    <ice:selectInputDate id="nacimiento"
                                         value="#{pacienteList.paciente.nacimiento}" renderAsPopup="true"
                                         partialSubmit="false" renderMonthAsDropdown="true"
                                         renderYearAsDropdown="true" style="width: 225px; display:inline"
                                         required="true" /><ice:message style="color:red;" id="nacimientoError" for="nacimiento"/>
                               </s:decorate>                                             
                     </ice:panelGroup>
                          <s:decorate id="searchdecId" template="layout/display.xhtml">
                               <ice:commandButton id="search" value="#{messages.search}"
                                    action="/PacienteList.xhtml" partialSubmit="true" />
                               <ice:commandButton id="reset" value="#{messages.reset}"
                                    action="#{pacienteList.reset()}" partialSubmit="true" />
                          </s:decorate>
                     </ice:panelGroup>
                </ice:form>




      ------------------- Date converter -------------------------

      @Name("jbSeam4413Converter")
      @BypassInterceptors
      @Converter
      public class JbSeam4413 implements javax.faces.convert.Converter {

        @Logger
        private Log log;

        public Object getAsObject(FacesContext context, UIComponent component,
                String value) throws ConverterException {
            log.info("JbSeam4413.getAsObject called (" + value +")");
            if(value == null || value.trim().length() == 0)
                return null;
            Date date = null;
            try {
                 SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
                date = sdf.parse(URLDecoder.decode(value,"UTF-8"));
            } catch (ParseException e) {
                e.printStackTrace();
                FacesMessage message = new FacesMessage();
                message.setDetail("javax.faces.converter.DateTimeConverter.DATE");
                message.setSummary("javax.faces.converter.DateTimeConverter.DATE_detail");
                message.setSeverity(FacesMessage.SEVERITY_ERROR);
                throw new ConverterException(message);
            } catch (UnsupportedEncodingException e) {
                 e.printStackTrace();
                FacesMessage message = new FacesMessage();
                message.setDetail("javax.faces.converter.DateTimeConverter.DATE");
                message.setSummary("javax.faces.converter.DateTimeConverter.DATE_detail");
                message.setSeverity(FacesMessage.SEVERITY_ERROR);
                throw new ConverterException(message);
           }
            return date;
        }

        public String getAsString(FacesContext context, UIComponent component,
                Object value) throws ConverterException {
            log.info("JbSeam4413.getAsString called");
            SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
            return sdf.format(value);
        }
      }


      -------------------------- Non ascii field converter --------------------------


      @Name("trimInputFields")
      @BypassInterceptors
      @Converter
      public class TrimInputFields implements javax.faces.convert.Converter{

           public Object getAsObject(FacesContext context, UIComponent component, String value) {
                if(StringUtils.isEmpty(value)){
                     return null;
                } else {
                     try {
                          return URLDecoder.decode(value,"UTF-8");
                     } catch (UnsupportedEncodingException e) {
                           FacesMessage message = new FacesMessage();
                          message.setDetail("javax.faces.converter.STRING");                   
                          message.setSeverity(FacesMessage.SEVERITY_ERROR);
                          throw new ConverterException(message);
                     }
                }
           }

           public String getAsString(FacesContext context, UIComponent component, Object value) {
             if(value!=null){
                  try {
                     return URLDecoder.decode(value.toString().trim(),"UTF-8");
                } catch (UnsupportedEncodingException e) {
                       FacesMessage message = new FacesMessage();
                     message.setDetail("javax.faces.converter.STRING");
                     message.setSummary(e.getLocalizedMessage());
                     message.setSeverity(FacesMessage.SEVERITY_ERROR);
                     throw new ConverterException(message);
                }
             } else {
                  return null;
             }
           }
      }

        • 1. Re: non ascii characters urlencoded by simple get
          seamfrappe

          It seems a icefaces bug.
          I changed my configuration to:
          Seam 2.2.0.GA with RichFaces on JBoss 5.1, then I configured JBoss to accept UTF-8, and voilá!


          Is not a seam defect, surely is IceFaces.


          Case is not closed.

          • 2. Re: non ascii characters urlencoded by simple get
            jguglielmin

            ICEfaces should work with UTF-8, so if it doesn't please open a jira and attach a simple test case where this isn't working for you.  If you assign it to me, then I can take a look. Thanks, Judy.

            • 3. Re: non ascii characters urlencoded by simple get
              seamfrappe

              Judy: My suspect on ICEFaces is because I regenerated the same project using seam-gen with RichFaces, then and all runs as expected. Maybe ICEFaces is not the problem but the combination with seam could be.



              Today I tried something diffrent: I enabled all verbosity on log4j, and I hang a phase listener, my findings are intresting:


              Seam calls HibernateEntityQuery:getResultList 3 times, first without parameters, second with right characters, and third with a urlencoded chars.


              I don't know how to make a test case.


              Below is my log:



              17:15:51,864 DEBUG PhaseLog:20 - Inicio fase RESTORE_VIEW 1
              17:15:51,864 DEBUG PhaseLog:16 - Fin fase RESTORE_VIEW 1
              17:15:51,864 DEBUG SessionFactoryObjectFactory:92 - JNDI lookup: visoreseceSessionFactory
              ...
              
              17:15:51,880 DEBUG JTATransaction:92 - Began a new JTA transaction
              17:15:51,880 DEBUG JDBCContext:199 - successfully registered Synchronization
              17:15:51,880 TRACE JDBCContext:237 - after transaction begin
              
              17:15:51,880 *DEBUG PhaseLog:20 - Inicio fase APPLY REQUEST_VALUES 2
              17:15:51,880 TRACE QueryPlanCache:98 - located HQL query plan in cache (select paciente from Paciente paciente)
              ...
              17:16:00,817 DEBUG StatefulPersistenceContext:860 - initializing non-lazy collections
              17:16:00,817 DEBUG PhaseLog:16 - Fin fase APPLY REQUEST_VALUES 2
              17:16:00,817 DEBUG PhaseLog:20 - Inicio fase PROCESS_VALIDATIONS 3
              17:16:00,833 DEBUG PhaseLog:16 - Fin fase PROCESS_VALIDATIONS 3
              17:16:00,833 DEBUG PhaseLog:20 - Inicio fase UPDATE_MODEL_VALUES 4
              ...
              17:16:00,848 TRACE QueryPlanCache:98 - located HQL query plan in cache (select paciente from Paciente paciente where lower(paciente.apPaterno) like lower(concat(:el3,'%')) and lower(paciente.sexo) like lower(concat(:el6,'%')) and paciente.nacimiento = :el7)
              ...
              17:16:00,880 TRACE DefaultAutoFlushEventListener:76 - Dont need to execute flush
              17:16:00,880 TRACE HQLQueryPlan:174 - find: select paciente from Paciente paciente where lower(paciente.apPaterno) like lower(concat(:el3,'%')) and lower(paciente.sexo) like lower(concat(:el6,'%')) and paciente.nacimiento = :el7
              



              Here is my non ascii character as Hibernate parameter:


              17:16:00,880 TRACE QueryParameters:278 - named parameters: {el6=MASCULINO, el3=Zuñiga, el7=12 octubre 1983}
              ...
              17:16:01,520 DEBUG PhaseLog:16 - Fin fase UPDATE_MODEL_VALUES 4
              17:16:01,520 DEBUG PhaseLog:20 - Inicio fase INVOKE_APPLICATION 5
              17:16:01,520 DEBUG PhaseLog:16 - Fin fase INVOKE_APPLICATION 5
              17:16:01,536 TRACE CacheSynchronization:114 - transaction after completion callback, status: 4
              17:16:01,536 TRACE JDBCContext:242 - after transaction completion
              17:16:01,536 TRACE SessionImpl:450 - after transaction completion
              17:16:01,661 DEBUG PhaseLog:20 - Inicio fase RESTORE_VIEW 1
              17:16:01,661 DEBUG PhaseLog:16 - Fin fase RESTORE_VIEW 1
              


              After this point my non ascii characters get urlencoded and the field is requeried against Hibernate:


              17:16:01,755 DEBUG SQL:111 - select top 11 paciente0_.CV_CURP as CV1_2_, paciente0_.CV_AGREGADO_MED as CV2_2_, paciente0_.TX_AP_MATERNO as TX3_2_, paciente0_.TX_AP_PATERNO as TX4_2_, paciente0_.CV_CURP_RENAPO as CV5_2_, paciente0_.TM_NACIMIENTO as TM6_2_, paciente0_.TX_NOMBRE as TX7_2_, paciente0_.CV_NSS as CV8_2_, (SELECT c.tx_entidad_federativa FROM CAT_ENTIDAD_FEDERATIVA c WHERE c.id_pais = paciente0_.id_pais_nacimiento AND c.id_entidad_federativa = paciente0_.id_entidad_federativa_nac) as formula5_, (SELECT c.tx_escolaridad FROM CAT_ESCOLARIDAD c WHERE c.id_escolaridad = paciente0_.id_escolaridad) as formula6_, (SELECT c.tx_edo_civil FROM CAT_EDO_CIVIL c WHERE c.id_edo_civil = paciente0_.id_edo_civil) as formula7_, (SELECT c.tx_grupo_sanguineo FROM CAT_GRUPO_SANGUINEO c WHERE c.id_grupo_sanguineo = paciente0_.id_grupo_sanguineo) as formula8_, (SELECT c.TX_OCUPACION FROM CAT_OCUPACION c WHERE c.ID_OCUPACION=paciente0_.ID_OCUPACION) as formula9_, (SELECT c.tx_pais FROM CAT_PAIS c WHERE c.id_pais = paciente0_.id_pais_nacimiento) as formula10_, (SELECT TOP 1 c.CT_RESULTADO FROM  MEDICIONES_PACIENTE c WHERE c.ID_MEDICION =303 AND c.CV_CURP=paciente0_.CV_CURP ORDER BY c.TM_EVENTO DESC) as formula11_, (SELECT c.tx_sexo FROM CAT_SEXO c WHERE c.id_sexo = paciente0_.id_sexo) as formula12_, (SELECT TOP 1 c.CT_RESULTADO FROM  MEDICIONES_PACIENTE c WHERE c.ID_MEDICION =301 AND c.CV_CURP=paciente0_.CV_CURP ORDER BY c.TM_EVENTO DESC) as formula13_ from EC.dbo.PACIENTE paciente0_ where (lower(paciente0_.TX_AP_PATERNO) like lower((?+'%'))) and (lower((SELECT c.tx_sexo FROM CAT_SEXO c WHERE c.id_sexo = paciente0_.id_sexo)) like lower((?+'%'))) and paciente0_.TM_NACIMIENTO=?
              Hibernate: select top 11 paciente0_.CV_CURP as CV1_2_, paciente0_.CV_AGREGADO_MED as CV2_2_, paciente0_.TX_AP_MATERNO as TX3_2_, paciente0_.TX_AP_PATERNO as TX4_2_, paciente0_.CV_CURP_RENAPO as CV5_2_, paciente0_.TM_NACIMIENTO as TM6_2_, paciente0_.TX_NOMBRE as TX7_2_, paciente0_.CV_NSS as CV8_2_, (SELECT c.tx_entidad_federativa FROM CAT_ENTIDAD_FEDERATIVA c WHERE c.id_pais = paciente0_.id_pais_nacimiento AND c.id_entidad_federativa = paciente0_.id_entidad_federativa_nac) as formula5_, (SELECT c.tx_escolaridad FROM CAT_ESCOLARIDAD c WHERE c.id_escolaridad = paciente0_.id_escolaridad) as formula6_, (SELECT c.tx_edo_civil FROM CAT_EDO_CIVIL c WHERE c.id_edo_civil = paciente0_.id_edo_civil) as formula7_, (SELECT c.tx_grupo_sanguineo FROM CAT_GRUPO_SANGUINEO c WHERE c.id_grupo_sanguineo = paciente0_.id_grupo_sanguineo) as formula8_, (SELECT c.TX_OCUPACION FROM CAT_OCUPACION c WHERE c.ID_OCUPACION=paciente0_.ID_OCUPACION) as formula9_, (SELECT c.tx_pais FROM CAT_PAIS c WHERE c.id_pais = paciente0_.id_pais_nacimiento) as formula10_, (SELECT TOP 1 c.CT_RESULTADO FROM  MEDICIONES_PACIENTE c WHERE c.ID_MEDICION =303 AND c.CV_CURP=paciente0_.CV_CURP ORDER BY c.TM_EVENTO DESC) as formula11_, (SELECT c.tx_sexo FROM CAT_SEXO c WHERE c.id_sexo = paciente0_.id_sexo) as formula12_, (SELECT TOP 1 c.CT_RESULTADO FROM  MEDICIONES_PACIENTE c WHERE c.ID_MEDICION =301 AND c.CV_CURP=paciente0_.CV_CURP ORDER BY c.TM_EVENTO DESC) as formula13_ from EC.dbo.PACIENTE paciente0_ where (lower(paciente0_.TX_AP_PATERNO) like lower((?+'%'))) and (lower((SELECT c.tx_sexo FROM CAT_SEXO c WHERE c.id_sexo = paciente0_.id_sexo)) like lower((?+'%'))) and paciente0_.TM_NACIMIENTO=?
              17:16:01,755 TRACE AbstractBatcher:513 - preparing statement
              17:16:01,755 TRACE StringType:151 - binding 'Zu%C3%B1iga' to parameter: 1
              17:16:01,755 TRACE StringType:151 - binding 'MASCULINO' to parameter: 2
              17:16:01,755 TRACE DateType:151 - binding '12 octubre 1983' to parameter: 3
              17:16:02,208 DEBUG AbstractBatcher:426 - about to open ResultSet (open ResultSets: 0, globally: 0)
              17:16:02,208 TRACE Loader:717 - processing result set
              17:16:02,208 TRACE Loader:744 - done processing result set (0 rows)
              17:16:02,208 DEBUG AbstractBatcher:433 - about to close ResultSet (open ResultSets: 1, globally: 1)
              17:16:02,208 DEBUG AbstractBatcher:418 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
              17:16:02,208 TRACE AbstractBatcher:562 - closing statement
              17:16:02,208 DEBUG ConnectionManager:427 - aggressively releasing JDBC connection
              17:16:02,208 DEBUG ConnectionManager:464 - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
              17:16:02,208 TRACE Loader:874 - total objects hydrated: 0
              17:16:02,208 DEBUG StatefulPersistenceContext:860 - initializing non-lazy collections
              17:16:02,224 DEBUG PhaseLog:16 - Fin fase RENDER_RESPONSE 6
              17:16:02,224 TRACE SessionImpl:1317 - setting flush mode to: AUTO
              17:16:02,224 TRACE SessionImpl:301 - closing session
              17:16:02,224 TRACE ConnectionManager:398 - connection already null in cleanup : no action
              17:16:02,224 TRACE CacheSynchronization:114 - transaction after completion callback, status: 4
              17:16:02,224 TRACE JDBCContext:242 - after transaction completion
              17:16:02,224 TRACE SessionImpl:450 - after transaction completion
              

              • 4. Re: non ascii characters urlencoded by simple get
                seamfrappe

                Finally I got the bug.
                It was not in Seam.


                After processing a request a redirect is thrown between seam and icefaces.
                Seam URLEncodes the resulting URI with parameters and redirects to IceFaces, then IceFaces urlencodes the urlencoded passed by Seam, this is not a problem with ascii characters, and with US-dateformat. But with non-ascii characters and with dates formated with /  this double encoding screws-up every parameter.



                My solution was to patch IceFaces source to avoid the double URLEncoding.


                Look at icefaces 1.8.2 source code on BridgeExternalContext at 412 line.
                     


                  redirector.redirect(encodeResourceURL(uri.toString()));
                




                I just changed this line to


                       


                redirector.redirect(encodeResourceURL(uriString));
                




                This is not an Icefaces forum, I know, but since I find this bug using Seam, the solution is posted here.


                • 5. Re: non ascii characters urlencoded by simple get
                  jguglielmin

                  This can be tracked at jira ICE-5172.


                  If you have a simple sample that you could attach for testing purposes, it would be appreciated.