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.context.FacesContext;
29  import javax.faces.el.MethodBinding;
30  import javax.faces.event.AbortProcessingException;
31  import javax.faces.event.ActionEvent;
32  import javax.faces.event.ActionListener;
33  import javax.faces.event.FacesEvent;
34  import javax.faces.event.PhaseId;
35  
36  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
37  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
38  import org.apache.myfaces.component.MethodBindingToMethodExpression;
39  import org.apache.myfaces.component.MethodExpressionToMethodBinding;
40  import org.apache.myfaces.custom.schedule.model.ScheduleDay;
41  import org.apache.myfaces.custom.schedule.model.ScheduleEntry;
42  
43  /**
44   * This class contains all 'interactive' stuff for the Schedule component, meaning
45   * actions and actionListeners.
46   * 
47   * @author Jurgen Lust
48   * @version $Revision: 736908 $
49   */
50  @JSFComponent
51  public class UISchedule extends org.apache.myfaces.custom.schedule.UIScheduleBase implements
52          Serializable, ActionSource2
53  {
54      public static final String COMPONENT_TYPE = "org.apache.myfaces.UISchedule";
55      
56      private class ScheduleActionListener implements ActionListener
57      {
58          //~ Methods ------------------------------------------------------------
59  
60          /**
61           * @see javax.faces.event.ActionListener#processAction(javax.faces.event.ActionEvent)
62           */
63          public void processAction(ActionEvent event)
64                  throws AbortProcessingException
65          {
66              UISchedule schedule = (UISchedule) event.getComponent();
67              ScheduleEntry entry = schedule.getSubmittedEntry();
68              schedule.getModel().setSelectedEntry(entry);
69              schedule.setSubmittedEntry(null);
70          }
71      }
72      
73      private static final long serialVersionUID = -8333458172939036755L;
74      //private MethodBinding _action;
75      private MethodBinding _actionListener;
76      private ScheduleActionListener _scheduleListener;
77      private ScheduleEntry _submittedEntry;
78      private Date _lastClickedDateAndTime = null;
79      
80  
81  
82  
83      public UISchedule()
84      {
85          super();
86          _scheduleListener = new ScheduleActionListener();
87      }
88  
89      public void addActionListener(ActionListener listener)
90      {
91          addFacesListener(listener);
92      }
93  
94      
95      /**
96       * @see javax.faces.component.UIComponent#broadcast(javax.faces.event.FacesEvent)
97       */
98      public void broadcast(FacesEvent event) throws AbortProcessingException
99      {
100         FacesContext context = getFacesContext();
101         //invoke the mouselistener first
102         if (event instanceof ScheduleMouseEvent)
103         {
104             ScheduleMouseEvent mouseEvent = (ScheduleMouseEvent) event;
105             MethodBinding mouseListener = getMouseListener();
106 
107             if (mouseListener != null)
108             {
109                 mouseListener.invoke(context,
110                         new Object[] { mouseEvent });
111             }
112         }
113         
114         //then invoke private ScheduleActionListener for set
115         //the selected entry (if exists), so other
116         //listeners can retrieve it from getSelectedEntry.
117         if (event.isAppropriateListener(_scheduleListener))
118         {
119             event.processListener(_scheduleListener);
120         }
121 
122         //then invoke any other listeners
123         super.broadcast(event);
124 
125         if (event instanceof ActionEvent)
126         {
127             //Call registered actionListener if applies
128             MethodBinding actionListener = getActionListener();
129     
130             if (actionListener != null)
131             {
132                 actionListener.invoke(context, new Object[] { event });
133             }
134             
135             //Since UISchedule is an ActionSource component,
136             //we should call to the application actionListener
137             //when an ActionEvent happens.
138             ActionListener defaultActionListener = context.getApplication()
139                 .getActionListener();
140             if (defaultActionListener != null)
141             {
142                 defaultActionListener.processAction((ActionEvent) event);
143             }
144         }
145     }
146 
147     /**
148      * Find the entry with the given id
149      *
150      * @param id the id
151      *
152      * @return the entry
153      */
154     protected ScheduleEntry findEntry(String id)
155     {
156         if (id == null)
157         {
158             return null;
159         }
160 
161         for (Iterator dayIterator = getModel().iterator(); dayIterator
162                 .hasNext();)
163         {
164             ScheduleDay day = (ScheduleDay) dayIterator.next();
165 
166             for (Iterator iter = day.iterator(); iter.hasNext();)
167             {
168                 ScheduleEntry entry = (ScheduleEntry) iter.next();
169 
170                 if (id.equals(entry.getId()))
171                 {
172                     return entry;
173                 }
174             }
175         }
176 
177         return null;
178     }
179     
180     /**
181      * @deprecated Use setActionExpression instead.
182      */
183     public void setAction(MethodBinding action)
184     {
185         if(action != null)
186         {
187             setActionExpression(new MethodBindingToMethodExpression(action));
188         } 
189         else
190         {
191             setActionExpression(null);
192         }
193     }
194 
195     /**
196      * @deprecated Use getActionExpression() instead.
197      */
198     public MethodBinding getAction()
199     {
200         MethodExpression actionExpression = getActionExpression();
201         if (actionExpression instanceof MethodBindingToMethodExpression) {
202             return ((MethodBindingToMethodExpression)actionExpression).getMethodBinding();
203         }
204         if(actionExpression != null)
205         {
206             return new MethodExpressionToMethodBinding(actionExpression);
207         }
208         return null;
209     }
210     
211     // Property: actionExpression
212     private MethodExpression _actionExpression;
213 
214     /**
215      * Gets Specifies the action to take when this command is invoked.
216      *         If the value is an expression, it is expected to be a method
217      *         binding EL expression that identifies an action method. An action method
218      *         accepts no parameters and has a String return value, called the action
219      *         outcome, that identifies the next view displayed. The phase that this
220      *         event is fired in can be controlled via the immediate attribute.
221      * 
222      *         If the value is a string literal, it is treated as a navigation outcome
223      *         for the current view.  This is functionally equivalent to a reference to
224      *         an action method that returns the string literal.
225      *
226      * @return  the new actionExpression value
227      */
228     @JSFProperty(
229         returnSignature="java.lang.String",
230        jspName="action")
231     public MethodExpression getActionExpression()
232     {
233       if (_actionExpression != null)
234       {
235         return _actionExpression;
236       }
237       ValueExpression expression = getValueExpression("actionExpression");
238       if (expression != null)
239       {
240         return (MethodExpression)expression.getValue(getFacesContext().getELContext());
241       }
242       return null;
243     }
244 
245     /**
246      * Sets Specifies the action to take when this command is invoked.
247      *         If the value is an expression, it is expected to be a method
248      *         binding EL expression that identifies an action method. An action method
249      *         accepts no parameters and has a String return value, called the action
250      *         outcome, that identifies the next view displayed. The phase that this
251      *         event is fired in can be controlled via the immediate attribute.
252      * 
253      *         If the value is a string literal, it is treated as a navigation outcome
254      *         for the current view.  This is functionally equivalent to a reference to
255      *         an action method that returns the string literal.
256      * 
257      * @param actionExpression  the new actionExpression value
258      */
259     public void setActionExpression(MethodExpression actionExpression)
260     {
261       this._actionExpression = actionExpression;
262     }
263     
264     
265     // Property: mouseListenerExpression
266     private MethodExpression _mouseListenerExpression;
267 
268     /**
269      *   
270      * @return
271      */
272     @JSFProperty(
273         returnSignature="void",
274         methodSignature="org.apache.myfaces.custom.schedule.ScheduleMouseEvent",
275         stateHolder=true,
276         jspName="mouseListener")
277     public MethodExpression getMouseListenerExpression()
278     {
279       if (_mouseListenerExpression != null)
280       {
281         return _mouseListenerExpression;
282       }
283       ValueExpression expression = getValueExpression("mouseListenerExpression");
284       if (expression != null)
285       {
286         return (MethodExpression)expression.getValue(getFacesContext().getELContext());
287       }
288       return null;
289     }
290 
291     public void setMouseListenerExpression(MethodExpression mouseListenerExpression)
292     {
293       this._mouseListenerExpression = mouseListenerExpression;
294     }    
295     
296     /*
297     public MethodBinding getAction()
298     {
299         return _action;
300     }*/
301 
302     /**
303      * 
304      */
305     @JSFProperty(
306         returnSignature="void",
307         methodSignature="javax.faces.event.ActionEvent")
308     public MethodBinding getActionListener()
309     {
310         return _actionListener;
311     }
312 
313     public ActionListener[] getActionListeners()
314     {
315         return (ActionListener[]) getFacesListeners(ActionListener.class);
316     }
317 
318     /**
319      * The last date and time of day that was clicked. This is set when
320      * submitOnClick is true, and the schedule is clicked by the user.
321      * 
322      * @return the last clicked date and time
323      */
324     @JSFProperty(tagExcluded = true)        
325     public Date getLastClickedDateAndTime()
326     {
327         return _lastClickedDateAndTime;
328     }
329     
330     /**
331      * @deprecated Use setMouseListenerExpression instead.
332      */
333     public void setMouseListener(MethodBinding mouseListener)
334     {
335         if(mouseListener != null)
336         {
337             setMouseListenerExpression(new MethodBindingToMethodExpression(mouseListener));
338         } 
339         else
340         {
341             setMouseListenerExpression(null);
342         }
343     }
344 
345     /**
346      *   
347      * @return the method binding to the mouse listener method
348      */
349     public MethodBinding getMouseListener()
350     {
351         MethodExpression mouseListenerExpression = getMouseListenerExpression();
352         if (mouseListenerExpression instanceof MethodBindingToMethodExpression) {
353             return ((MethodBindingToMethodExpression)mouseListenerExpression).getMethodBinding();
354         }
355         if(mouseListenerExpression != null)
356         {
357             return new MethodExpressionToMethodBinding(mouseListenerExpression);
358         }
359         return null;
360     }
361 
362     /**
363      * @return the submittedEntry
364      */
365     public ScheduleEntry getSubmittedEntry()
366     {
367         return _submittedEntry;
368     }
369 
370     /**
371      * @see javax.faces.component.UIComponent#queueEvent(javax.faces.event.FacesEvent)
372      */
373     public void queueEvent(FacesEvent event)
374     {
375         if (event instanceof ActionEvent || event instanceof ScheduleMouseEvent)
376         {
377             if (isImmediate())
378             {
379                 event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
380             }
381             else
382             {
383                 event.setPhaseId(PhaseId.INVOKE_APPLICATION);
384             }
385         }
386 
387         super.queueEvent(event);
388     }
389 
390     public void removeActionListener(ActionListener listener)
391     {
392         removeFacesListener(listener);
393     }
394 
395     /**
396      * This method is invoked at the beginning of the restore view phase,
397      * resetting all mouse event variables that were left from the previous
398      * request
399      */
400     protected void resetMouseEvents()
401     {
402         this._lastClickedDateAndTime = null;
403     }
404 
405     /**
406      * @see org.apache.myfaces.custom.schedule.UIScheduleBase#restoreState(javax.faces.context.FacesContext, java.lang.Object)
407      */
408     public void restoreState(FacesContext context, Object state)
409     {
410         Object[] values = (Object[]) state;
411         super.restoreState(context, values[0]);
412         _lastClickedDateAndTime = (Date) values[1];
413         _actionListener = (MethodBinding) restoreAttachedState(context,
414                 values[2]);
415         _actionExpression = (MethodExpression) restoreAttachedState(context, values[3]);
416         _mouseListenerExpression = (MethodExpression) restoreAttachedState(context, values[4]);
417     }
418     
419     /**
420      * @see org.apache.myfaces.custom.schedule.UIScheduleBase#saveState(javax.faces.context.FacesContext)
421      */
422     public Object saveState(FacesContext context)
423     {
424         Object[] values = new Object[5];
425         values[0] = super.saveState(context);
426         values[1] = _lastClickedDateAndTime;
427         values[2] = saveAttachedState(context, _actionListener);
428         values[3] = saveAttachedState(context, _actionExpression);
429         values[4] = saveAttachedState(context, _mouseListenerExpression);
430         
431         return values;
432     }
433 
434     
435 
436     public void setActionListener(MethodBinding actionListener)
437     {
438         this._actionListener = actionListener;
439     }
440 
441     
442     
443     /**
444      * The last date and time of day that was clicked. This is set when
445      * submitOnClick is true, and the schedule is clicked by the user.
446      * 
447      * @return the last clicked date and time
448      */
449     protected void setLastClickedDateAndTime(Date lastClickedDateAndTime)
450     {
451         this._lastClickedDateAndTime = lastClickedDateAndTime;
452     }
453 
454 
455     /**
456      * @param submittedEntry the submittedEntry to set
457      */
458     protected void setSubmittedEntry(ScheduleEntry submittedEntry)
459     {
460         this._submittedEntry = submittedEntry;
461     }
462     
463 }