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.schedule;
20  
21  import java.io.Serializable;
22  import java.util.Date;
23  import java.util.Iterator;
24  
25  import javax.el.MethodExpression;
26  import javax.el.ValueExpression;
27  import javax.faces.component.ActionSource2;
28  import javax.faces.component.PartialStateHolder;
29  import javax.faces.component.StateHolder;
30  import javax.faces.context.FacesContext;
31  import javax.faces.el.MethodBinding;
32  import javax.faces.event.AbortProcessingException;
33  import javax.faces.event.ActionEvent;
34  import javax.faces.event.ActionListener;
35  import javax.faces.event.FacesEvent;
36  import javax.faces.event.PhaseId;
37  
38  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
39  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
40  import org.apache.myfaces.component.AttachedDeltaWrapper;
41  import org.apache.myfaces.component.MethodBindingToMethodExpression;
42  import org.apache.myfaces.component.MethodExpressionToMethodBinding;
43  import org.apache.myfaces.custom.schedule.model.ScheduleDay;
44  import org.apache.myfaces.custom.schedule.model.ScheduleEntry;
45  
46  /**
47   * This class contains all 'interactive' stuff for the Schedule component, meaning
48   * actions and actionListeners.
49   * 
50   * @author Jurgen Lust
51   * @version $Revision: 736908 $
52   */
53  @JSFComponent
54  public class UISchedule extends org.apache.myfaces.custom.schedule.UIScheduleBase implements
55          Serializable, ActionSource2
56  {
57      public static final String COMPONENT_TYPE = "org.apache.myfaces.UISchedule";
58      
59      private class ScheduleActionListener implements ActionListener
60      {
61          //~ Methods ------------------------------------------------------------
62  
63          /**
64           * @see javax.faces.event.ActionListener#processAction(javax.faces.event.ActionEvent)
65           */
66          public void processAction(ActionEvent event)
67                  throws AbortProcessingException
68          {
69              UISchedule schedule = (UISchedule) event.getComponent();
70              ScheduleEntry entry = schedule.getSubmittedEntry();
71              schedule.getModel().setSelectedEntry(entry);
72              schedule.setSubmittedEntry(null);
73          }
74      }
75      
76      private static final long serialVersionUID = -8333458172939036755L;
77      //private MethodBinding _action;
78      private MethodBinding _actionListener;
79      private ScheduleActionListener _scheduleListener;
80      private ScheduleEntry _submittedEntry;
81      //private Date _lastClickedDateAndTime = null;
82      
83  
84  
85  
86      public UISchedule()
87      {
88          super();
89          _scheduleListener = new ScheduleActionListener();
90      }
91  
92      public void addActionListener(ActionListener listener)
93      {
94          addFacesListener(listener);
95      }
96  
97      
98      /**
99       * @see javax.faces.component.UIComponent#broadcast(javax.faces.event.FacesEvent)
100      */
101     public void broadcast(FacesEvent event) throws AbortProcessingException
102     {
103         FacesContext context = getFacesContext();
104         //invoke the mouselistener first
105         if (event instanceof ScheduleMouseEvent)
106         {
107             ScheduleMouseEvent mouseEvent = (ScheduleMouseEvent) event;
108             MethodBinding mouseListener = getMouseListener();
109 
110             if (mouseListener != null)
111             {
112                 mouseListener.invoke(context,
113                         new Object[] { mouseEvent });
114             }
115         }
116         
117         //then invoke private ScheduleActionListener for set
118         //the selected entry (if exists), so other
119         //listeners can retrieve it from getSelectedEntry.
120         if (event.isAppropriateListener(_scheduleListener))
121         {
122             event.processListener(_scheduleListener);
123         }
124 
125         //then invoke any other listeners
126         super.broadcast(event);
127 
128         if (event instanceof ActionEvent)
129         {
130             //Call registered actionListener if applies
131             MethodBinding actionListener = getActionListener();
132     
133             if (actionListener != null)
134             {
135                 actionListener.invoke(context, new Object[] { event });
136             }
137             
138             //Since UISchedule is an ActionSource component,
139             //we should call to the application actionListener
140             //when an ActionEvent happens.
141             ActionListener defaultActionListener = context.getApplication()
142                 .getActionListener();
143             if (defaultActionListener != null)
144             {
145                 defaultActionListener.processAction((ActionEvent) event);
146             }
147         }
148     }
149 
150     /**
151      * Find the entry with the given id
152      *
153      * @param id the id
154      *
155      * @return the entry
156      */
157     protected ScheduleEntry findEntry(String id)
158     {
159         if (id == null)
160         {
161             return null;
162         }
163 
164         for (Iterator dayIterator = getModel().iterator(); dayIterator
165                 .hasNext();)
166         {
167             ScheduleDay day = (ScheduleDay) dayIterator.next();
168 
169             for (Iterator iter = day.iterator(); iter.hasNext();)
170             {
171                 ScheduleEntry entry = (ScheduleEntry) iter.next();
172 
173                 if (id.equals(entry.getId()))
174                 {
175                     return entry;
176                 }
177             }
178         }
179 
180         return null;
181     }
182     
183     /**
184      * @deprecated Use setActionExpression instead.
185      */
186     public void setAction(MethodBinding action)
187     {
188         if(action != null)
189         {
190             setActionExpression(new MethodBindingToMethodExpression(action));
191         } 
192         else
193         {
194             setActionExpression(null);
195         }
196     }
197 
198     /**
199      * @deprecated Use getActionExpression() instead.
200      */
201     public MethodBinding getAction()
202     {
203         MethodExpression actionExpression = getActionExpression();
204         if (actionExpression instanceof MethodBindingToMethodExpression) {
205             return ((MethodBindingToMethodExpression)actionExpression).getMethodBinding();
206         }
207         if(actionExpression != null)
208         {
209             return new MethodExpressionToMethodBinding(actionExpression);
210         }
211         return null;
212     }
213     
214     // Property: actionExpression
215     private MethodExpression _actionExpression;
216 
217     /**
218      * Gets Specifies the action to take when this command is invoked.
219      *         If the value is an expression, it is expected to be a method
220      *         binding EL expression that identifies an action method. An action method
221      *         accepts no parameters and has a String return value, called the action
222      *         outcome, that identifies the next view displayed. The phase that this
223      *         event is fired in can be controlled via the immediate attribute.
224      * 
225      *         If the value is a string literal, it is treated as a navigation outcome
226      *         for the current view.  This is functionally equivalent to a reference to
227      *         an action method that returns the string literal.
228      *
229      * @return  the new actionExpression value
230      */
231     @JSFProperty(
232         returnSignature="java.lang.String",
233        jspName="action")
234     public MethodExpression getActionExpression()
235     {
236       if (_actionExpression != null)
237       {
238         return _actionExpression;
239       }
240       ValueExpression expression = getValueExpression("actionExpression");
241       if (expression != null)
242       {
243         return (MethodExpression)expression.getValue(getFacesContext().getELContext());
244       }
245       return null;
246     }
247 
248     /**
249      * Sets Specifies the action to take when this command is invoked.
250      *         If the value is an expression, it is expected to be a method
251      *         binding EL expression that identifies an action method. An action method
252      *         accepts no parameters and has a String return value, called the action
253      *         outcome, that identifies the next view displayed. The phase that this
254      *         event is fired in can be controlled via the immediate attribute.
255      * 
256      *         If the value is a string literal, it is treated as a navigation outcome
257      *         for the current view.  This is functionally equivalent to a reference to
258      *         an action method that returns the string literal.
259      * 
260      * @param actionExpression  the new actionExpression value
261      */
262     public void setActionExpression(MethodExpression actionExpression)
263     {
264       this._actionExpression = actionExpression;
265       if (initialStateMarked())
266       {
267           getStateHelper().put(PropertyKeys.actionExpressionSet,Boolean.TRUE);
268       }
269     }
270     
271     private boolean _isSetActionExpression()
272     {
273         Boolean value = (Boolean) getStateHelper().get(PropertyKeys.actionExpressionSet);
274         return value == null ? false : value;
275     }
276     
277     // Property: mouseListenerExpression
278     private MethodExpression _mouseListenerExpression;
279 
280     /**
281      *   
282      * @return
283      */
284     @JSFProperty(
285         returnSignature="void",
286         methodSignature="org.apache.myfaces.custom.schedule.ScheduleMouseEvent",
287         stateHolder=true,
288         jspName="mouseListener")
289     public MethodExpression getMouseListenerExpression()
290     {
291       if (_mouseListenerExpression != null)
292       {
293         return _mouseListenerExpression;
294       }
295       ValueExpression expression = getValueExpression("mouseListenerExpression");
296       if (expression != null)
297       {
298         return (MethodExpression)expression.getValue(getFacesContext().getELContext());
299       }
300       return null;
301     }
302 
303     public void setMouseListenerExpression(MethodExpression mouseListenerExpression)
304     {
305       this._mouseListenerExpression = mouseListenerExpression;
306       if (initialStateMarked())
307       {
308           getStateHelper().put(PropertyKeys.mouseListenerExpressionSet,Boolean.TRUE);
309       }
310     }    
311     
312     /*
313     public MethodBinding getAction()
314     {
315         return _action;
316     }*/
317 
318     /**
319      * 
320      */
321     @JSFProperty(
322         returnSignature="void",
323         methodSignature="javax.faces.event.ActionEvent")
324     public MethodBinding getActionListener()
325     {
326         return _actionListener;
327     }
328 
329     public ActionListener[] getActionListeners()
330     {
331         return (ActionListener[]) getFacesListeners(ActionListener.class);
332     }
333 
334     /**
335      * The last date and time of day that was clicked. This is set when
336      * submitOnClick is true, and the schedule is clicked by the user.
337      * 
338      * @return the last clicked date and time
339      */
340     @JSFProperty(tagExcluded = true)        
341     public Date getLastClickedDateAndTime()
342     {
343         return (Date) getStateHelper().get(PropertyKeys.lastClickedDateAndTime);
344     }
345     
346     /**
347      * @deprecated Use setMouseListenerExpression instead.
348      */
349     public void setMouseListener(MethodBinding mouseListener)
350     {
351         if(mouseListener != null)
352         {
353             setMouseListenerExpression(new MethodBindingToMethodExpression(mouseListener));
354         } 
355         else
356         {
357             setMouseListenerExpression(null);
358         }
359     }
360 
361     /**
362      *   
363      * @return the method binding to the mouse listener method
364      */
365     public MethodBinding getMouseListener()
366     {
367         MethodExpression mouseListenerExpression = getMouseListenerExpression();
368         if (mouseListenerExpression instanceof MethodBindingToMethodExpression) {
369             return ((MethodBindingToMethodExpression)mouseListenerExpression).getMethodBinding();
370         }
371         if(mouseListenerExpression != null)
372         {
373             return new MethodExpressionToMethodBinding(mouseListenerExpression);
374         }
375         return null;
376     }
377 
378     /**
379      * @return the submittedEntry
380      */
381     public ScheduleEntry getSubmittedEntry()
382     {
383         return _submittedEntry;
384     }
385 
386     /**
387      * @see javax.faces.component.UIComponent#queueEvent(javax.faces.event.FacesEvent)
388      */
389     public void queueEvent(FacesEvent event)
390     {
391         if (event instanceof ActionEvent || event instanceof ScheduleMouseEvent)
392         {
393             if (isImmediate())
394             {
395                 event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
396             }
397             else
398             {
399                 event.setPhaseId(PhaseId.INVOKE_APPLICATION);
400             }
401         }
402 
403         super.queueEvent(event);
404     }
405 
406     public void removeActionListener(ActionListener listener)
407     {
408         removeFacesListener(listener);
409     }
410 
411     /**
412      * This method is invoked at the beginning of the restore view phase,
413      * resetting all mouse event variables that were left from the previous
414      * request
415      */
416     protected void resetMouseEvents()
417     {
418         getStateHelper().put(PropertyKeys.lastClickedDateAndTime, null);
419     }
420 
421     /**
422      * @see org.apache.myfaces.custom.schedule.UIScheduleBase#restoreState(javax.faces.context.FacesContext, java.lang.Object)
423      */
424     public void restoreState(FacesContext facesContext, Object state)
425     {
426         if (state == null)
427         {
428             return;
429         }
430         
431         Object[] values = (Object[])state;
432         super.restoreState(facesContext,values[0]);
433         if (values[1] instanceof AttachedDeltaWrapper)
434         {
435             //Delta
436             ((StateHolder)_actionListener).restoreState(facesContext, ((AttachedDeltaWrapper) values[1]).getWrappedStateObject());
437         }
438         else
439         {
440             //Full
441             _actionListener = (javax.faces.el.MethodBinding) restoreAttachedState(facesContext,values[1]);
442         }         
443         if (values[2] instanceof AttachedDeltaWrapper)
444         {
445             //Delta
446             ((StateHolder)_actionExpression).restoreState(facesContext, ((AttachedDeltaWrapper) values[2]).getWrappedStateObject());
447         }
448         else
449         {
450             //Full
451             _actionExpression = (javax.el.MethodExpression) restoreAttachedState(facesContext,values[2]);
452         }         
453         if (values[3] instanceof AttachedDeltaWrapper)
454         {
455             //Delta
456             ((StateHolder)_mouseListenerExpression).restoreState(facesContext, ((AttachedDeltaWrapper) values[3]).getWrappedStateObject());
457         }
458         else
459         {
460             //Full
461             _mouseListenerExpression = (javax.el.MethodExpression) restoreAttachedState(facesContext,values[3]);
462         }         
463     }
464     
465     /**
466      * @see org.apache.myfaces.custom.schedule.UIScheduleBase#saveState(javax.faces.context.FacesContext)
467      */
468     public Object saveState(FacesContext facesContext)
469     {
470         if (initialStateMarked())
471         {
472             boolean nullDelta = true;
473             Object parentSaved = super.saveState(facesContext);
474             Object actionListenerSaved = null;
475             if (!_isSetActionListener() &&
476                 _actionListener != null && _actionListener instanceof PartialStateHolder)
477             {
478                 //Delta
479                 StateHolder holder = (StateHolder) _actionListener;
480                 if (!holder.isTransient())
481                 {
482                     Object attachedState = holder.saveState(facesContext);
483                     if (attachedState != null)
484                     {
485                         nullDelta = false;
486                     }
487                     actionListenerSaved = new AttachedDeltaWrapper(_actionListener.getClass(),
488                         attachedState);
489                 }
490             }
491             else  if (_isSetActionListener() || _actionListener != null)
492             {
493                 //Full
494                 actionListenerSaved = saveAttachedState(facesContext,_actionListener);
495                 nullDelta = false;
496             }        
497             Object actionExpressionSaved = null;
498             if (!_isSetActionExpression() &&
499                 _actionExpression != null && _actionExpression instanceof PartialStateHolder)
500             {
501                 //Delta
502                 StateHolder holder = (StateHolder) _actionExpression;
503                 if (!holder.isTransient())
504                 {
505                     Object attachedState = holder.saveState(facesContext);
506                     if (attachedState != null)
507                     {
508                         nullDelta = false;
509                     }
510                     actionExpressionSaved = new AttachedDeltaWrapper(_actionExpression.getClass(),
511                         attachedState);
512                 }
513             }
514             else  if (_isSetActionExpression() || _actionExpression != null)
515             {
516                 //Full
517                 actionExpressionSaved = saveAttachedState(facesContext,_actionExpression);
518                 nullDelta = false;
519             }        
520             Object mouseListenerExpressionSaved = null;
521             if (!_isSetActionListener() &&
522                 _mouseListenerExpression != null && _mouseListenerExpression instanceof PartialStateHolder)
523             {
524                 //Delta
525                 StateHolder holder = (StateHolder) _mouseListenerExpression;
526                 if (!holder.isTransient())
527                 {
528                     Object attachedState = holder.saveState(facesContext);
529                     if (attachedState != null)
530                     {
531                         nullDelta = false;
532                     }
533                     mouseListenerExpressionSaved = new AttachedDeltaWrapper(_mouseListenerExpression.getClass(),
534                         attachedState);
535                 }
536             }
537             else  if (_isSetActionListener() || _mouseListenerExpression != null)
538             {
539                 //Full
540                 mouseListenerExpressionSaved = saveAttachedState(facesContext,_mouseListenerExpression);
541                 nullDelta = false;
542             }        
543             if (parentSaved == null && nullDelta)
544             {
545                 //No values
546                 return null;
547             }
548             
549             Object[] values = new Object[4];
550             values[0] = parentSaved;
551             values[1] = actionListenerSaved;
552             values[2] = actionExpressionSaved;
553             values[3] = mouseListenerExpressionSaved;
554             return values;
555         }
556         else
557         {
558             Object[] values = new Object[4];
559             values[0] = super.saveState(facesContext);
560             values[1] = saveAttachedState(facesContext, _actionListener);
561             values[2] = saveAttachedState(facesContext, _actionExpression);
562             values[3] = saveAttachedState(facesContext, _mouseListenerExpression);
563             return values;
564         }
565     }
566 
567     
568 
569     public void setActionListener(MethodBinding actionListener)
570     {
571         this._actionListener = actionListener;
572         if (initialStateMarked())
573         {
574             getStateHelper().put(PropertyKeys.actionListenerSet,Boolean.TRUE);
575         }
576     }
577 
578     private boolean _isSetActionListener()
579     {
580         Boolean value = (Boolean) getStateHelper().get(PropertyKeys.actionListenerSet);
581         return value == null ? false : value;
582     }
583     
584     /**
585      * The last date and time of day that was clicked. This is set when
586      * submitOnClick is true, and the schedule is clicked by the user.
587      * 
588      * @return the last clicked date and time
589      */
590     protected void setLastClickedDateAndTime(Date lastClickedDateAndTime)
591     {
592         getStateHelper().put(PropertyKeys.lastClickedDateAndTime, lastClickedDateAndTime);
593     }
594 
595 
596     /**
597      * @param submittedEntry the submittedEntry to set
598      */
599     protected void setSubmittedEntry(ScheduleEntry submittedEntry)
600     {
601         this._submittedEntry = submittedEntry;
602     }
603     
604     protected enum PropertyKeys
605     {
606         lastClickedDateAndTime
607         , actionExpressionSet
608         , actionListenerSet
609         , mouseListenerExpressionSet
610     }
611 }