You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2009/02/17 16:42:48 UTC

svn commit: r745124 - in /myfaces/tomahawk/trunk/core/src: main/java/org/apache/myfaces/custom/date/ test/java/org/apache/myfaces/custom/date/

Author: lu4242
Date: Tue Feb 17 15:42:47 2009
New Revision: 745124

URL: http://svn.apache.org/viewvc?rev=745124&view=rev
Log:
TOMAHAWK-1014 HTMLInputDate ignores custom converters (changed decode and encodeEnd so converters can be set).

Modified:
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/AbstractHtmlInputDate.java
    myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/HtmlDateRenderer.java
    myfaces/tomahawk/trunk/core/src/test/java/org/apache/myfaces/custom/date/HtmlDateRendererTest.java

Modified: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/AbstractHtmlInputDate.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/AbstractHtmlInputDate.java?rev=745124&r1=745123&r2=745124&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/AbstractHtmlInputDate.java (original)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/AbstractHtmlInputDate.java Tue Feb 17 15:42:47 2009
@@ -342,39 +342,36 @@
     public abstract boolean isDisabled();
 
     /**
-     * This component converts submitted values to its inner class
-     * UserData, so this method does not allow custom
-     * converters to be defined.
+     * Retrieve the converter used by this component. 
+     * <p>
+     * If no converter is selected, submitted values are converted to 
+     * its inner class UserData on decode method.
+     * </p>
+     * <p>
+     * If some converter is used, submitted values are decoded as
+     * a String with the following format:
+     * </p>
+     * <p></p>
+     * <p>year=yyyy</p>
+     * <p>month=mm</p>
+     * <p>day=dd</p>
+     * <p>hours=hh</p>
+     * <p>minutes=mm</p>
+     * <p>seconds=ss</p>
+     * <p>ampm=ampm</p>
+     * <p></p>
+     * <p>
+     * Note that submitted values could be wrong and it is necessary to
+     * restore values on render response phase. The converter receive 
+     * a string with this format on getAsObject method and it is expected
+     * the converter encode it on getAsString method, so the renderer can
+     * restore the submitted values correctly.
+     * </p>
      * 
      * @JSFProperty
-     *   tagExcluded = "true"
      */
     public Converter getConverter()
     {
-        return null;
-    }
-    
-    public void setConverter(Converter converter)
-    {
-        throw new UnsupportedOperationException();
-    }
-    
-    /**
-     * This property comes from 1.2 UIInput, but since this
-     * component does not allow a custom converter, this
-     * should return null.
-     * 
-     * @JSFProperty
-     *   tagExcluded = "true"
-     * @return
-     */
-    public String getConverterMessage()
-    {
-        return null;
-    }
-    
-    public void setConverterMessage(String converterMessage)
-    {
-        throw new UnsupportedOperationException();
+        return super.getConverter();
     }
 }

Modified: myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/HtmlDateRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/HtmlDateRenderer.java?rev=745124&r1=745123&r2=745124&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/HtmlDateRenderer.java (original)
+++ myfaces/tomahawk/trunk/core/src/main/java/org/apache/myfaces/custom/date/HtmlDateRenderer.java Tue Feb 17 15:42:47 2009
@@ -19,11 +19,14 @@
 package org.apache.myfaces.custom.date;
 
 import java.io.IOException;
+import java.io.StringReader;
 import java.text.DateFormatSymbols;
 import java.text.ParseException;
 import java.util.Calendar;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
 
 import javax.faces.application.FacesMessage;
 import javax.faces.component.UIComponent;
@@ -85,12 +88,63 @@
 
         HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
         Locale currentLocale = facesContext.getViewRoot().getLocale();
-        UserData userData = (UserData) inputDate.getSubmittedValue();
-        if( userData == null )
-            userData = inputDate.getUserData(currentLocale);
+        UserData userData = null;
         String type = inputDate.getType();
         boolean ampm = inputDate.isAmpm();
         String clientId = uiComponent.getClientId(facesContext);
+        
+        if (null == inputDate.getConverter())
+        {
+            userData = (UserData) inputDate.getSubmittedValue();
+            if( userData == null )
+                userData = inputDate.getUserData(currentLocale);
+        }
+        else
+        {
+            //Use converter to get the value as string and
+            //create a UserData decoding it.
+            String value = org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getStringValue(facesContext, inputDate);
+            
+            //Create a UserData bean
+            userData = inputDate.getUserData(currentLocale);
+            
+            if (null != value)
+            {
+                StringTokenizer st = new StringTokenizer(value,"\n");
+                while(st.hasMoreTokens())
+                {
+                    String token = st.nextToken();
+                    if (token.startsWith("year="))
+                    {
+                        userData.setYear(token.substring(5));
+                    }
+                    if (token.startsWith("month="))
+                    {
+                        userData.setYear(token.substring(6));
+                    }
+                    if (token.startsWith("day="))
+                    {
+                        userData.setYear(token.substring(4));
+                    }
+                    if (token.startsWith("hours="))
+                    {
+                        userData.setYear(token.substring(6));
+                    }
+                    if (token.startsWith("minutes="))
+                    {
+                        userData.setYear(token.substring(8));
+                    }
+                    if (token.startsWith("seconds="))
+                    {
+                        userData.setYear(token.substring(8));
+                    }
+                    if (token.startsWith("ampm="))
+                    {
+                        userData.setYear(token.substring(5));
+                    }
+                }
+            }
+        }
 
         boolean disabled = isDisabled(facesContext, inputDate);
         boolean readonly = inputDate.isReadonly();
@@ -334,42 +388,122 @@
 
         if( isDisabled(facesContext, inputDate) ) // For safety, do not set the submited value if the component is disabled.
             return;
+        
+        if (null == inputDate.getConverter())
+        {
+            //Instead of use a custom object to encode data,
+            //we have to encode all info in a String, so the converter
+            //can convert it to a String if the value
+            //is invalid.
+            String clientId = inputDate.getClientId(facesContext);
+            String type = inputDate.getType();
+            Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
+            StringBuffer submittedValue = new StringBuffer();
+            if( ! (type.equals( "time" ) || type.equals( "short_time" )) )
+            {
+                submittedValue.append("year=");
+                submittedValue.append((String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
+                submittedValue.append("\n");
+
+                submittedValue.append("month=");
+                submittedValue.append((String) requestMap.get(clientId + ID_MONTH_POSTFIX));
+                submittedValue.append("\n");
+                
+                submittedValue.append("day=");
+                submittedValue.append((String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
+                submittedValue.append("\n");                
+            }
+            
+            if( ! type.equals( "date" ) )
+            {
+                submittedValue.append("hours=");
+                submittedValue.append((String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
+                submittedValue.append("\n");
+                
+                submittedValue.append("minutes=");
+                submittedValue.append((String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
+                submittedValue.append("\n");
+
+                if (type.equals("full") || type.equals("time"))
+                {
+                    submittedValue.append("seconds=");
+                    submittedValue.append((String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
+                    submittedValue.append("\n");                    
+                }
+                
+                if (inputDate.isAmpm())
+                {
+                    submittedValue.append("ampm=");
+                    submittedValue.append((String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
+                    submittedValue.append("\n");
+                }
+            }
+            if (submittedValue.charAt(submittedValue.length()-1) == '\n' )
+            {
+                submittedValue.deleteCharAt(submittedValue.length()-1);
+            }
+            
+            inputDate.setSubmittedValue( submittedValue.toString() );
+        }
+        else
+        {
+            //Use AbstractHtmlInputDate.UserData to save submitted value
+            Locale currentLocale = facesContext.getViewRoot().getLocale();
+            UserData userData = (UserData) inputDate.getSubmittedValue();
+            if( userData == null )
+                userData = inputDate.getUserData(currentLocale);
+
+            String clientId = inputDate.getClientId(facesContext);
+            String type = inputDate.getType();
+            Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
+
+            if( ! (type.equals( "time" ) || type.equals( "short_time" )) ){
+                userData.setDay( (String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
+                userData.setMonth( (String) requestMap.get(clientId + ID_MONTH_POSTFIX) );
+                userData.setYear( (String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
+            }
 
-        Locale currentLocale = facesContext.getViewRoot().getLocale();
-        UserData userData = (UserData) inputDate.getSubmittedValue();
-        if( userData == null )
-            userData = inputDate.getUserData(currentLocale);
-
-        String clientId = inputDate.getClientId(facesContext);
-        String type = inputDate.getType();
-        Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
-
-        if( ! (type.equals( "time" ) || type.equals( "short_time" )) ){
-            userData.setDay( (String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
-            userData.setMonth( (String) requestMap.get(clientId + ID_MONTH_POSTFIX) );
-            userData.setYear( (String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
-        }
-
-        if( ! type.equals( "date" ) ){
-            userData.setHours( (String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
-            userData.setMinutes( (String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
-            if (type.equals("full") || type.equals("time"))
-                userData.setSeconds( (String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
-
-            if (inputDate.isAmpm()) {
-                userData.setAmpm( (String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
+            if( ! type.equals( "date" ) ){
+                userData.setHours( (String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
+                userData.setMinutes( (String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
+                if (type.equals("full") || type.equals("time"))
+                    userData.setSeconds( (String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
+
+                if (inputDate.isAmpm()) {
+                    userData.setAmpm( (String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
+                }
             }
+            inputDate.setSubmittedValue( userData );
         }
-        inputDate.setSubmittedValue( userData );
     }
-
+    
     public Object getConvertedValue(FacesContext context, UIComponent uiComponent, Object submittedValue) throws ConverterException {
-        UserData userData = (UserData) submittedValue;
-        try {
-            return userData.parse();
-        } catch (ParseException e) {
-            Object[] args = {uiComponent.getId()};
-            throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, DATE_MESSAGE_ID, args));
+        
+        HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
+        
+        if (inputDate.getConverter() == null)
+        {
+            UserData userData = (UserData) submittedValue;
+            try {
+                return userData.parse();
+            } catch (ParseException e) {
+                Object[] args = {uiComponent.getId()};
+                throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, DATE_MESSAGE_ID, args));
+            }            
+        }
+        else
+        {
+            if (submittedValue != null && !(submittedValue instanceof String))
+            {
+                if (RendererUtils.NOTHING.equals(submittedValue))
+                {
+                    return null;
+                }
+                throw new IllegalArgumentException("Submitted value of type String for component : "
+                        + RendererUtils.getPathToComponent(inputDate) + "expected");
+            }
+            
+            return inputDate.getConverter().getAsObject(context, inputDate, (String) submittedValue);
         }
     }
 }

Modified: myfaces/tomahawk/trunk/core/src/test/java/org/apache/myfaces/custom/date/HtmlDateRendererTest.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/test/java/org/apache/myfaces/custom/date/HtmlDateRendererTest.java?rev=745124&r1=745123&r2=745124&view=diff
==============================================================================
--- myfaces/tomahawk/trunk/core/src/test/java/org/apache/myfaces/custom/date/HtmlDateRendererTest.java (original)
+++ myfaces/tomahawk/trunk/core/src/test/java/org/apache/myfaces/custom/date/HtmlDateRendererTest.java Tue Feb 17 15:42:47 2009
@@ -19,17 +19,25 @@
 
 package org.apache.myfaces.custom.date;
 
+import java.io.IOException;
+import java.io.StringReader;
+import java.text.ParseException;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Properties;
 
 import javax.faces.FactoryFinder;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.convert.ConverterException;
 import javax.faces.render.RenderKitFactory;
 
 import junit.framework.Test;
@@ -37,6 +45,7 @@
 
 import org.apache.myfaces.application.ApplicationFactoryImpl;
 import org.apache.myfaces.custom.date.AbstractHtmlInputDate.UserData;
+import org.apache.myfaces.shared_tomahawk.util.MessageUtils;
 import org.apache.myfaces.test.AbstractTomahawkViewControllerTestCase;
 import org.apache.myfaces.test.utils.HtmlCheckAttributesUtil;
 import org.apache.myfaces.test.utils.HtmlRenderedAttr;
@@ -207,6 +216,240 @@
     assertEquals(cal.get(Calendar.YEAR) + "", data.getYear());
   }
 
+  public static class DateTestConverter implements Converter
+  {
+
+    public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String submittedValue)
+            throws ConverterException
+    {
+        HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
+        String type = inputDate.getType();
+        Properties props = new Properties();
+        try
+        {
+            props.load(new StringReader(submittedValue));
+        }catch(IOException e)
+        {
+        }
+        UserData userData = inputDate.getUserData(facesContext.getViewRoot().getLocale());
+        if( ! (type.equals( "time" ) || type.equals( "short_time" )) )
+        {
+            userData.setYear(props.getProperty("year"));
+            userData.setMonth(props.getProperty("month"));
+            userData.setDay(props.getProperty("day"));
+        }
+        
+        if( ! type.equals( "date" ) ){
+            userData.setHours(props.getProperty("hours"));
+            userData.setMinutes(props.getProperty("minutes"));
+            if (type.equals("full") || type.equals("time"))
+            {
+                userData.setSeconds(props.getProperty("seconds"));
+            }
+            if (inputDate.isAmpm()) {
+                userData.setAmpm(props.getProperty("ampm"));
+            }
+        }
+        try {
+            return userData.parse();
+        } catch (ParseException e) {
+            Object[] args = {uiComponent.getId()};
+            throw new ConverterException("Error Parsing");
+        }  
+    }
+
+    public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object submitValue)
+            throws ConverterException
+    {
+        HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
+        String type = inputDate.getType();
+        UserData value = new UserData((Date) submitValue, 
+                facesContext.getViewRoot().getLocale(), 
+                inputDate.getTimeZone(), inputDate.isAmpm(), inputDate.getType());        
+        
+        StringBuffer submittedValue = new StringBuffer();
+        if( ! (type.equals( "time" ) || type.equals( "short_time" )) )
+        {
+            submittedValue.append("year=");
+            submittedValue.append((String) value.getYear() );
+            submittedValue.append("\n");
+
+            submittedValue.append("month=");
+            submittedValue.append((String) value.getMonth());
+            submittedValue.append("\n");
+            
+            submittedValue.append("day=");
+            submittedValue.append((String) value.getDay() );
+            submittedValue.append("\n");                
+        }
+        
+        if( ! type.equals( "date" ) )
+        {
+            submittedValue.append("hours=");
+            submittedValue.append((String) value.getHours() );
+            submittedValue.append("\n");
+            
+            submittedValue.append("minutes=");
+            submittedValue.append((String) value.getMinutes() );
+            submittedValue.append("\n");
+
+            if (type.equals("full") || type.equals("time"))
+            {
+                submittedValue.append("seconds=");
+                submittedValue.append((String) value.getSeconds() );
+                submittedValue.append("\n");                    
+            }
+            
+            if (inputDate.isAmpm())
+            {
+                submittedValue.append("ampm=");
+                submittedValue.append((String) value.getAmpm() );
+                submittedValue.append("\n");
+            }
+        }
+        if (submittedValue.charAt(submittedValue.length()-1) == '\n' )
+        {
+            submittedValue.deleteCharAt(submittedValue.length()-1);
+        }
+        
+        return submittedValue.toString();
+    }
+      
+  }
+  
+  public void testDecodeConverterDate() throws Exception {
+      HtmlInputDate inputDate = new HtmlInputDate();
+      inputDate.setId("test");
+      inputDate.setType("date");
+      inputDate.setConverter(new DateTestConverter());
+      HtmlDateRenderer subject = new HtmlDateRenderer();
+      // setup the request map
+      Map map = new HashMap();
+      map.put("test.day", "14");
+      map.put("test.month", "1");
+      map.put("test.year", "2005");
+      FacesContext facesContext = mockupForDecodeCall(map);
+      // decode
+      subject.decode(facesContext, inputDate);
+      //With converter, the submitted value is a String
+      assertTrue(inputDate.getSubmittedValue() instanceof String);
+      // converter
+      inputDate.validate(facesContext);
+      
+      UserData data = inputDate.getUserData(Locale.ENGLISH);
+      assertEquals("14", data.getDay());
+      assertEquals("1", data.getMonth());
+      assertEquals("2005", data.getYear());
+    }
+  
+  public void testDecodeConverterWithSubmittedValue() throws Exception {
+      HtmlInputDate inputDate = new HtmlInputDate();
+      inputDate.setId("test");
+      inputDate.setType("date");
+      inputDate.setConverter(new DateTestConverter());
+      Date today = new Date();
+      inputDate.setSubmittedValue(new UserData(today, Locale.ENGLISH, null, true, "date"));
+      HtmlDateRenderer subject = new HtmlDateRenderer();
+      // setup the request map
+      Map map = new HashMap();
+      map.put("test.day", "14");
+      map.put("test.month", "1");
+      map.put("test.year", "2005");
+      FacesContext facesContext = mockupForDecodeCall(map);
+      // decode
+      subject.decode(facesContext, inputDate);
+      //With converter, the submitted value is a String
+      assertTrue(inputDate.getSubmittedValue() instanceof String);
+      // converter
+      inputDate.validate(facesContext);
+      
+      UserData data = inputDate.getUserData(Locale.ENGLISH);
+      assertEquals("14", data.getDay());
+      assertEquals("1", data.getMonth());
+      assertEquals("2005", data.getYear());
+    }
+  
+  public void testDecodeConverterTime() throws Exception {
+      HtmlInputDate inputDate = new HtmlInputDate();
+      inputDate.setId("test");
+      inputDate.setType("time");
+      HtmlDateRenderer subject = new HtmlDateRenderer();
+      // setup the request map
+      Map map = new HashMap();
+      map.put("test.hours", "12");
+      map.put("test.minutes", "15");
+      map.put("test.seconds", "35");
+      FacesContext facesContext = mockupForDecodeCall(map);
+      // decode
+      subject.decode(facesContext, inputDate);
+      //With converter, the submitted value is a String
+      assertTrue(inputDate.getSubmittedValue() instanceof String);
+      // converter
+      inputDate.validate(facesContext);
+      
+      UserData data = inputDate.getUserData(Locale.ENGLISH);
+      assertEquals("12", data.getHours());
+      assertEquals("15", data.getMinutes());
+      assertEquals("35", data.getSeconds());
+    }
+
+  public void testDecodeConverterFull() throws Exception {
+      HtmlInputDate inputDate = new HtmlInputDate();
+      inputDate.setId("test");
+      inputDate.setType("full");
+      HtmlDateRenderer subject = new HtmlDateRenderer();
+      // setup the request map
+      Map map = new HashMap();
+      map.put("test.day", "14");
+      map.put("test.month", "1");
+      map.put("test.year", "2005");
+      map.put("test.hours", "12");
+      map.put("test.minutes", "15");
+      map.put("test.seconds", "3");
+      FacesContext facesContext = mockupForDecodeCall(map);
+      // decode
+      subject.decode(facesContext, inputDate);
+      //With converter, the submitted value is a String
+      assertTrue(inputDate.getSubmittedValue() instanceof String);
+      // converter
+      inputDate.validate(facesContext);
+      UserData data = inputDate.getUserData(Locale.ENGLISH);
+      assertEquals("14", data.getDay());
+      assertEquals("1", data.getMonth());
+      assertEquals("2005", data.getYear());
+      assertEquals("12", data.getHours());
+      assertEquals("15", data.getMinutes());
+      assertEquals("03", data.getSeconds());
+    }
+
+    public void testDecodeConverterFlorp() throws Exception {
+      HtmlInputDate inputDate = new HtmlInputDate();
+      inputDate.setId("test");
+      // is this correct? Should it parse correctly if the type is not valid?
+      inputDate.setType("florp");
+      HtmlDateRenderer subject = new HtmlDateRenderer();
+      // setup the request map
+      Map map = new HashMap();
+      map.put("test.day", "14");
+      map.put("test.month", "1");
+      map.put("test.year", "2005");
+      map.put("test.hours", "12");
+      map.put("test.minutes", "15");
+      FacesContext facesContext = mockupForDecodeCall(map);
+      // decode
+      subject.decode(facesContext, inputDate);
+      //With converter, the submitted value is a String
+      assertTrue(inputDate.getSubmittedValue() instanceof String);
+      // converter
+      inputDate.validate(facesContext);
+      UserData data = inputDate.getUserData(Locale.ENGLISH);
+      assertEquals("14", data.getDay());
+      assertEquals("1", data.getMonth());
+      assertEquals("2005", data.getYear());
+      assertEquals("12", data.getHours());
+      assertEquals("15", data.getMinutes());
+    }
+
   /*
    * Test method for
    * 'org.apache.myfaces.custom.date.HtmlDateRenderer.encodeEnd(FacesContext,