View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.date;
20  
21  import java.io.IOException;
22  import java.text.DateFormatSymbols;
23  import java.text.ParseException;
24  import java.util.Calendar;
25  import java.util.Date;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.StringTokenizer;
30  
31  import javax.faces.application.FacesMessage;
32  import javax.faces.component.UIComponent;
33  import javax.faces.component.behavior.ClientBehavior;
34  import javax.faces.component.behavior.ClientBehaviorHolder;
35  import javax.faces.context.FacesContext;
36  import javax.faces.context.ResponseWriter;
37  import javax.faces.convert.ConverterException;
38  import javax.faces.event.ComponentSystemEvent;
39  import javax.faces.event.ComponentSystemEventListener;
40  import javax.faces.event.ListenerFor;
41  
42  import org.apache.myfaces.component.UserRoleUtils;
43  import org.apache.myfaces.custom.calendar.DateBusinessConverter;
44  import org.apache.myfaces.custom.calendar.DefaultDateBusinessConverter;
45  import org.apache.myfaces.custom.calendar.FunctionCallProvider;
46  import org.apache.myfaces.custom.calendar.HtmlCalendarRenderer;
47  import org.apache.myfaces.custom.calendar.HtmlCalendarRenderer.CalendarDateTimeConverter;
48  import org.apache.myfaces.custom.date.AbstractHtmlInputDate.UserData;
49  import org.apache.myfaces.shared_tomahawk.renderkit.JSFAttr;
50  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
51  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
52  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRenderer;
53  import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
54  import org.apache.myfaces.shared_tomahawk.renderkit.html.util.JavascriptUtils;
55  import org.apache.myfaces.shared_tomahawk.renderkit.html.util.ResourceUtils;
56  import org.apache.myfaces.shared_tomahawk.util.MessageUtils;
57  import org.apache.myfaces.tomahawk.application.PreRenderViewAddResourceEvent;
58  import org.apache.myfaces.tomahawk.util.Constants;
59  
60  /**
61   * @JSFRenderer
62   *   renderKitId = "HTML_BASIC" 
63   *   family = "javax.faces.Input"
64   *   type = "org.apache.myfaces.Date"
65   * 
66   * @author Sylvain Vieujot (latest modification by $Author: lu4242 $)
67   * @version $Revision: 745285 $ $Date: 2009-02-17 17:52:58 -0500 (mar, 17 feb 2009) $
68   */
69  @ListenerFor(systemEventClass=PreRenderViewAddResourceEvent.class)
70  public class HtmlDateRenderer extends HtmlRenderer
71      implements ComponentSystemEventListener
72  {
73      /**
74       * <p>The message identifier of the {@link FacesMessage} to be created if
75       * the input is not a valid date.</p>
76       */
77      public static final String DATE_MESSAGE_ID = "org.apache.myfaces.Date.INVALID";
78  
79      private static final String ID_DAY_POSTFIX = ".day";
80      private static final String ID_MONTH_POSTFIX = ".month";
81      private static final String ID_YEAR_POSTFIX = ".year";
82      private static final String ID_HOURS_POSTFIX = ".hours";
83      private static final String ID_MINUTES_POSTFIX = ".minutes";
84      private static final String ID_SECONDS_POSTFIX = ".seconds";
85      private static final String ID_AMPM_POSTFIX = ".ampm";
86  
87      static public String getClientIdForDaySubcomponent(String clientId)
88      {
89          return clientId + ID_DAY_POSTFIX;
90      }
91      
92      public void processEvent(ComponentSystemEvent event)
93      {
94          HtmlInputDate inputDate = (HtmlInputDate) event.getComponent();
95          FacesContext facesContext = FacesContext.getCurrentInstance();
96          String type = inputDate.getType();
97          boolean disabled = isDisabled(facesContext, inputDate);
98          boolean readonly = inputDate.isReadonly();
99          if( ! (type.equals("time") || type.equals("short_time")))
100         {
101             if( inputDate.isPopupCalendar() && ! disabled && ! readonly )
102             {
103                 HtmlCalendarRenderer.addScriptAndCSSResourcesWithJSF2ResourceAPI(facesContext,inputDate);
104             }
105         }
106     }
107     
108     protected boolean isDisabled(FacesContext facesContext, HtmlInputDate inputDate) {
109         if( !UserRoleUtils.isEnabledOnUserRole(inputDate) )
110             return false;
111 
112         return inputDate.isDisabled();
113     }
114 
115     public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {
116         RendererUtils.checkParamValidity(facesContext, uiComponent, HtmlInputDate.class);
117 
118         HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
119         Locale currentLocale = facesContext.getViewRoot().getLocale();
120         UserData userData = null;
121         String type = inputDate.getType();
122         boolean ampm = inputDate.isAmpm();
123         String clientId = uiComponent.getClientId(facesContext);
124         
125         Map<String, List<ClientBehavior>> behaviors = inputDate.getClientBehaviors();
126         if (!behaviors.isEmpty())
127         {
128             ResourceUtils.renderDefaultJsfJsInlineIfNecessary(facesContext, facesContext.getResponseWriter());
129         }        
130         
131         if (null == inputDate.getConverter())
132         {
133             userData = (UserData) inputDate.getSubmittedValue();
134             if( userData == null )
135                 userData = inputDate.getUserData(currentLocale);
136         }
137         else
138         {
139             //Use converter to get the value as string and
140             //create a UserData decoding it.
141             String value = org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getStringValue(facesContext, inputDate);
142             
143             //Create a UserData bean
144             userData = inputDate.getUserData(currentLocale);
145             
146             if (null != value)
147             {
148                 StringTokenizer st = new StringTokenizer(value,"\n");
149                 while(st.hasMoreTokens())
150                 {
151                     String token = st.nextToken();
152                     if (token.startsWith("year="))
153                     {
154                         userData.setYear(token.substring(5));
155                     }
156                     if (token.startsWith("month="))
157                     {
158                         userData.setMonth(token.substring(6));
159                     }
160                     if (token.startsWith("day="))
161                     {
162                         userData.setDay(token.substring(4));
163                     }
164                     if (token.startsWith("hours="))
165                     {
166                         userData.setHours(token.substring(6));
167                     }
168                     if (token.startsWith("minutes="))
169                     {
170                         userData.setMinutes(token.substring(8));
171                     }
172                     if (token.startsWith("seconds="))
173                     {
174                         userData.setSeconds(token.substring(8));
175                     }
176                     if (token.startsWith("ampm="))
177                     {
178                         userData.setAmpm(token.substring(5));
179                     }
180                 }
181             }
182         }
183 
184         boolean disabled = isDisabled(facesContext, inputDate);
185         boolean readonly = inputDate.isReadonly();
186 
187         ResponseWriter writer = facesContext.getResponseWriter();
188 
189         HtmlRendererUtils.writePrettyLineSeparator(facesContext);
190 
191         writer.startElement(HTML.SPAN_ELEM, uiComponent);
192         writer.writeAttribute(HTML.ID_ATTR, clientId, null);
193 
194         if( ! (type.equals("time") || type.equals("short_time"))){
195             encodeInputDay(facesContext, inputDate, writer, clientId, userData, disabled, readonly);
196             encodeInputMonth(facesContext, inputDate, writer, clientId, userData, currentLocale, disabled, readonly);
197             encodeInputYear(facesContext, inputDate, writer, clientId, userData, disabled, readonly);
198 
199             if( inputDate.isPopupCalendar() && ! disabled && ! readonly )
200                 encodePopupCalendarButton(facesContext, uiComponent, writer, clientId, currentLocale);
201         }
202         if( type.equals("both") || type.equals("full")){
203             writer.write(" ");
204         }
205         if( ! type.equals("date")){
206             encodeInputHours(facesContext, uiComponent, writer, clientId, userData, disabled, readonly);
207             writer.write(":");
208             encodeInputMinutes(facesContext, uiComponent, writer, clientId, userData, disabled, readonly);
209             if (type.equals("full")|| type.equals("time")) {
210                         writer.write(":");
211                 encodeInputSeconds(facesContext, uiComponent, writer, clientId, userData, disabled, readonly);
212                     }
213             if (ampm) {
214                 encodeInputAmpm(facesContext, uiComponent, writer, clientId, userData, disabled, readonly, currentLocale);
215             }
216         }
217 
218         writer.endElement(HTML.SPAN_ELEM);
219     }
220 
221     protected void encodeInputField(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String id,
222             String value, int size, boolean disabled, boolean readonly)  throws IOException {
223         writer.startElement(HTML.INPUT_ELEM, uiComponent);
224         HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.UNIVERSAL_ATTRIBUTES);
225         Map<String, List<ClientBehavior>> behaviors = null;
226         if (uiComponent instanceof ClientBehaviorHolder)
227         {
228             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
229         }
230                 
231         if (behaviors != null && !behaviors.isEmpty())
232         {
233             HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent, behaviors);
234             HtmlRendererUtils.renderBehaviorizedFieldEventHandlersWithoutOnchange(facesContext, writer, uiComponent, behaviors);
235             HtmlRendererUtils.renderBehaviorizedOnchangeEventHandler(facesContext, writer, uiComponent, behaviors);
236         }
237         else
238         {
239             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.EVENT_HANDLER_ATTRIBUTES);
240             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
241         }
242         HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.INPUT_ATTRIBUTES);
243 
244 
245         if (disabled) {
246             writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
247         }
248         if( readonly ) {
249             writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, null);
250         }
251 
252         writer.writeAttribute(HTML.ID_ATTR, id, null);
253         writer.writeAttribute(HTML.NAME_ATTR, id, null);
254         writer.writeAttribute(HTML.SIZE_ATTR, Integer.toString(size), null);
255         writer.writeAttribute(HTML.MAXLENGTH_ATTR, Integer.toString(size), null);
256         if (value != null) {
257             writer.writeAttribute(HTML.VALUE_ATTR, value, null);
258         }
259         writer.endElement(HTML.INPUT_ELEM);
260     }
261 
262     protected void encodeInputDay(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId,
263             UserData userData, boolean disabled, boolean readonly) throws IOException {
264         encodeInputField(facesContext, uiComponent, writer, getClientIdForDaySubcomponent(clientId), userData.getDay(), 2, disabled, readonly);
265     }
266 
267     protected void encodeInputMonth(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId, UserData userData, Locale currentLocale,
268             boolean disabled, boolean readonly) throws IOException {
269         writer.startElement(HTML.SELECT_ELEM, uiComponent);
270         writer.writeAttribute(HTML.ID_ATTR, clientId + ID_MONTH_POSTFIX, null);
271         writer.writeAttribute(HTML.NAME_ATTR, clientId + ID_MONTH_POSTFIX, null);
272         writer.writeAttribute(HTML.SIZE_ATTR, "1", null);
273         HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.UNIVERSAL_ATTRIBUTES);
274         Map<String, List<ClientBehavior>> behaviors = null;
275         if (uiComponent instanceof ClientBehaviorHolder)
276         {
277             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
278         }
279                 
280         if (behaviors != null && !behaviors.isEmpty())
281         {
282             HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent, behaviors);
283             HtmlRendererUtils.renderBehaviorizedFieldEventHandlers(facesContext, writer, uiComponent, behaviors);
284         }
285         else
286         {
287             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.EVENT_HANDLER_ATTRIBUTES);
288             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
289         }        
290 
291         if (disabled) {
292             writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
293         }
294         if (readonly) {
295             writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, null);
296         }
297 
298         int selectedMonth = userData.getMonth() == null ? -1 : Integer.parseInt(userData.getMonth())-1;
299 
300         String[] months = HtmlCalendarRenderer.mapMonths(new DateFormatSymbols(currentLocale));
301         encodeEmptyInputMonthSelection(uiComponent, writer, selectedMonth);
302         for (int i = 0; i < months.length; i++) {
303             String monthName = months[i];
304             String monthNumber = Integer.toString(i+1);
305 
306             writer.write("\t\t");
307             writer.startElement(HTML.OPTION_ELEM, uiComponent);
308             writer.writeAttribute(HTML.VALUE_ATTR, monthNumber, null);
309 
310             if (i == selectedMonth)
311                 writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
312 
313             writer.writeText(monthName, null);
314 
315             writer.endElement(HTML.OPTION_ELEM);
316         }
317 
318         // bug #970747: force separate end tag
319         writer.writeText("", null);
320         writer.endElement(HTML.SELECT_ELEM);
321     }
322 
323     protected void encodeEmptyInputMonthSelection(UIComponent component, ResponseWriter writer, int selectedMonth) throws IOException{
324          writer.startElement(HTML.OPTION_ELEM, component);
325          writer.writeAttribute(HTML.VALUE_ATTR, "-1", null);
326 
327          if(selectedMonth == -1)
328              writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
329 
330          writer.writeText(((HtmlInputDate)component).getEmptyMonthSelection(), null);
331          writer.endElement(HTML.OPTION_ELEM);
332     }
333 
334     protected void encodeInputYear(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId,
335             UserData userData, boolean disabled, boolean readonly) throws IOException {
336         encodeInputField(facesContext, uiComponent, writer, clientId + ID_YEAR_POSTFIX, userData.getYear(), 4, disabled, readonly);
337     }
338 
339     protected void encodeInputHours(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId,
340             UserData userData, boolean disabled, boolean readonly) throws IOException {
341         encodeInputField(facesContext, uiComponent, writer, clientId + ID_HOURS_POSTFIX, userData.getHours(), 2, disabled, readonly);
342     }
343 
344     protected void encodeInputMinutes(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId,
345             UserData userData, boolean disabled, boolean readonly) throws IOException {
346         encodeInputField(facesContext, uiComponent, writer, clientId + ID_MINUTES_POSTFIX, userData.getMinutes(), 2, disabled, readonly);
347     }
348 
349     protected void encodeInputSeconds(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId,
350             UserData userData, boolean disabled, boolean readonly) throws IOException {
351         encodeInputField(facesContext, uiComponent, writer, clientId + ID_SECONDS_POSTFIX, userData.getSeconds(), 2, disabled, readonly);
352     }
353 
354     protected void encodeAmpmChoice(DateFormatSymbols symbols, UIComponent uiComponent, ResponseWriter writer, int calendar_ampm, int selected) throws IOException {
355         String[] ampm_choices = symbols.getAmPmStrings();
356         writer.write("\t\t");
357         writer.startElement(HTML.OPTION_ELEM, uiComponent);
358         writer.writeAttribute(HTML.VALUE_ATTR, new Integer(calendar_ampm), null);
359         if (calendar_ampm == selected)
360             writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
361         writer.writeText(ampm_choices[calendar_ampm], null);
362         writer.endElement(HTML.OPTION_ELEM);
363     }
364 
365     protected void encodeInputAmpm(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId,
366             UserData userData, boolean disabled, boolean readonly, Locale currentLocale) throws IOException {
367         writer.startElement(HTML.SELECT_ELEM, uiComponent);
368         writer.writeAttribute(HTML.ID_ATTR, clientId + ID_AMPM_POSTFIX, null);
369         writer.writeAttribute(HTML.NAME_ATTR, clientId + ID_AMPM_POSTFIX, null);
370         writer.writeAttribute(HTML.SIZE_ATTR, "1", null);
371         HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.UNIVERSAL_ATTRIBUTES);
372         Map<String, List<ClientBehavior>> behaviors = null;
373         if (uiComponent instanceof ClientBehaviorHolder)
374         {
375             behaviors = ((ClientBehaviorHolder) uiComponent).getClientBehaviors();
376         }
377                 
378         if (behaviors != null && !behaviors.isEmpty())
379         {
380             HtmlRendererUtils.renderBehaviorizedEventHandlers(facesContext, writer, uiComponent, behaviors);
381             HtmlRendererUtils.renderBehaviorizedFieldEventHandlers(facesContext, writer, uiComponent, behaviors);
382         }
383         else
384         {
385             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.EVENT_HANDLER_ATTRIBUTES);
386             HtmlRendererUtils.renderHTMLAttributes(writer, uiComponent, HTML.COMMON_FIELD_EVENT_ATTRIBUTES);
387         } 
388 
389         if (disabled) {
390             writer.writeAttribute(HTML.DISABLED_ATTR, Boolean.TRUE, null);
391         }
392         if (readonly) {
393             writer.writeAttribute(HTML.READONLY_ATTR, Boolean.TRUE, null);
394         }
395 
396         DateFormatSymbols symbols = new DateFormatSymbols(currentLocale);
397 
398         int selectedAmpm = userData.getAmpm() == null ? -1 : Integer.parseInt(userData.getAmpm());
399         encodeEmtypAmpmChoice(uiComponent, writer, selectedAmpm);
400         encodeAmpmChoice(symbols, uiComponent, writer, Calendar.AM, selectedAmpm);
401         encodeAmpmChoice(symbols, uiComponent, writer, Calendar.PM, selectedAmpm);
402 
403 
404         // bug #970747: force separate end tag
405         writer.writeText("", null);
406         writer.endElement(HTML.SELECT_ELEM);
407     }
408 
409     protected void encodeEmtypAmpmChoice(UIComponent component, ResponseWriter writer, int selectedAmpm) throws IOException{
410          writer.startElement(HTML.OPTION_ELEM, component);
411          writer.writeAttribute(HTML.VALUE_ATTR, "-1", null);
412 
413          if(selectedAmpm == -1)
414              writer.writeAttribute(HTML.SELECTED_ATTR, HTML.SELECTED_ATTR, null);
415 
416          writer.writeText(((HtmlInputDate)component).getEmptyAmpmSelection(), null);
417          writer.endElement(HTML.OPTION_ELEM);
418     }
419 
420     protected void encodePopupCalendarButton(FacesContext facesContext, UIComponent uiComponent, ResponseWriter writer, String clientId, Locale currentLocale) throws IOException{
421 
422         DateFormatSymbols symbols = new DateFormatSymbols(currentLocale);
423 
424         HtmlCalendarRenderer.addScriptAndCSSResources(facesContext,uiComponent);
425 
426         String calendarVar = JavascriptUtils.getValidJavascriptName(
427                 uiComponent.getClientId(facesContext)+"CalendarVar",false);
428         String dateFormat = CalendarDateTimeConverter.createJSPopupFormat(facesContext, null);
429 
430         String localizedLanguageScript = HtmlCalendarRenderer.getLocalizedLanguageScript(facesContext,
431                                             symbols,Calendar.getInstance(currentLocale).getFirstDayOfWeek(),
432                                             uiComponent,calendarVar);
433 
434         writer.startElement(HTML.SPAN_ELEM,uiComponent);
435         writer.writeAttribute(HTML.ID_ATTR,uiComponent.getClientId(facesContext)+"Span",
436                 JSFAttr.ID_ATTR);
437         writer.endElement(HTML.SPAN_ELEM);
438 
439         writer.startElement(HTML.SCRIPT_ELEM,uiComponent);
440         writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR,HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
441 
442         writer.writeText("var "+calendarVar+"=new org_apache_myfaces_PopupCalendar();\n",null);
443         writer.write(localizedLanguageScript);
444         writer.writeText(calendarVar+".init(document.getElementById('"+
445                 uiComponent.getClientId(facesContext)+"Span"+"'));\n",null);
446 
447 
448         writer.endElement(HTML.SCRIPT_ELEM);
449      HtmlCalendarRenderer.getScriptBtn(writer, facesContext, uiComponent,
450                 dateFormat,"...",new FunctionCallProvider(){
451             public String getFunctionCall(FacesContext facesContext, UIComponent uiComponent, String dateFormat)
452             {
453                 String clientId = uiComponent.getClientId(facesContext);
454 
455                 String clientVar = JavascriptUtils.getValidJavascriptName(clientId+"CalendarVar",true);
456 
457                 return clientVar+"._popUpCalendarForInputDate('"+clientId+"','"+dateFormat+"');";
458 
459             }
460         });
461     }
462 
463     public void decode(FacesContext facesContext, UIComponent uiComponent) {
464         RendererUtils.checkParamValidity(facesContext, uiComponent, HtmlInputDate.class);
465 
466         HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
467 
468         if( isDisabled(facesContext, inputDate) ) // For safety, do not set the submited value if the component is disabled.
469             return;
470         
471         if (null != inputDate.getConverter())
472         {
473             //Instead of use a custom object to encode data,
474             //we have to encode all info in a String, so the converter
475             //can convert it to a String if the value
476             //is invalid.
477             String clientId = inputDate.getClientId(facesContext);
478             String type = inputDate.getType();
479             Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
480             StringBuffer submittedValue = new StringBuffer();
481             if( ! (type.equals( "time" ) || type.equals( "short_time" )) )
482             {
483                 submittedValue.append("year=");
484                 submittedValue.append((String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
485                 submittedValue.append("\n");
486 
487                 submittedValue.append("month=");
488                 submittedValue.append((String) requestMap.get(clientId + ID_MONTH_POSTFIX));
489                 submittedValue.append("\n");
490                 
491                 submittedValue.append("day=");
492                 submittedValue.append((String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
493                 submittedValue.append("\n");                
494             }
495             
496             if( ! type.equals( "date" ) )
497             {
498                 submittedValue.append("hours=");
499                 submittedValue.append((String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
500                 submittedValue.append("\n");
501                 
502                 submittedValue.append("minutes=");
503                 submittedValue.append((String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
504                 submittedValue.append("\n");
505 
506                 if (type.equals("full") || type.equals("time"))
507                 {
508                     submittedValue.append("seconds=");
509                     submittedValue.append((String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
510                     submittedValue.append("\n");                    
511                 }
512                 
513                 if (inputDate.isAmpm())
514                 {
515                     submittedValue.append("ampm=");
516                     submittedValue.append((String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
517                     submittedValue.append("\n");
518                 }
519             }
520             if (submittedValue.charAt(submittedValue.length()-1) == '\n' )
521             {
522                 submittedValue.deleteCharAt(submittedValue.length()-1);
523             }
524             
525             inputDate.setSubmittedValue( submittedValue.toString() );
526         }
527         else
528         {
529             //Use AbstractHtmlInputDate.UserData to save submitted value
530             Locale currentLocale = facesContext.getViewRoot().getLocale();
531             UserData userData = (UserData) inputDate.getSubmittedValue();
532             if( userData == null )
533                 userData = inputDate.getUserData(currentLocale);
534 
535             String clientId = inputDate.getClientId(facesContext);
536             String type = inputDate.getType();
537             Map requestMap = facesContext.getExternalContext().getRequestParameterMap();
538 
539             if( ! (type.equals( "time" ) || type.equals( "short_time" )) ){
540                 userData.setDay( (String) requestMap.get(getClientIdForDaySubcomponent(clientId)) );
541                 userData.setMonth( (String) requestMap.get(clientId + ID_MONTH_POSTFIX) );
542                 userData.setYear( (String) requestMap.get(clientId + ID_YEAR_POSTFIX) );
543             }
544 
545             if( ! type.equals( "date" ) ){
546                 userData.setHours( (String) requestMap.get(clientId + ID_HOURS_POSTFIX) );
547                 userData.setMinutes( (String) requestMap.get(clientId + ID_MINUTES_POSTFIX) );
548                 if (type.equals("full") || type.equals("time"))
549                     userData.setSeconds( (String) requestMap.get(clientId + ID_SECONDS_POSTFIX) );
550 
551                 if (inputDate.isAmpm()) {
552                     userData.setAmpm( (String) requestMap.get(clientId + ID_AMPM_POSTFIX) );
553                 }
554             }
555             inputDate.setSubmittedValue( userData );
556         }
557         
558         HtmlRendererUtils.decodeClientBehaviors(facesContext, inputDate);
559     }
560 
561     private DateBusinessConverter getDateBusinessConverter(AbstractHtmlInputDate component)
562     {
563         DateBusinessConverter dateBusinessConverter = component.getDateBusinessConverter(); 
564         if (dateBusinessConverter == null)
565         {
566             dateBusinessConverter = new DefaultDateBusinessConverter();
567         }
568         return dateBusinessConverter;
569     }
570     
571     public Object getConvertedValue(FacesContext context, UIComponent uiComponent, Object submittedValue) throws ConverterException {
572         
573         HtmlInputDate inputDate = (HtmlInputDate) uiComponent;
574         
575         if (inputDate.getConverter() == null)
576         {
577             UserData userData = (UserData) submittedValue;
578             Date date = null;
579             try {
580                 date = userData.parse();
581             } catch (ParseException e) {
582                 Object[] args = {uiComponent.getId()};
583                 throw new ConverterException(MessageUtils.getMessage(Constants.TOMAHAWK_DEFAULT_BUNDLE, FacesMessage.SEVERITY_ERROR, DATE_MESSAGE_ID, args, context));
584             }
585             
586             return getDateBusinessConverter(inputDate).getBusinessValue(context, inputDate, date);
587         }
588         else
589         {
590             if (submittedValue != null && !(submittedValue instanceof String))
591             {
592                 if (RendererUtils.NOTHING.equals(submittedValue))
593                 {
594                     return null;
595                 }
596                 throw new IllegalArgumentException("Submitted value of type String for component : "
597                         + RendererUtils.getPathToComponent(inputDate) + "expected");
598             }
599             
600             return inputDate.getConverter().getAsObject(context, inputDate, (String) submittedValue);
601         }
602     }
603 }