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.taglib.core;
20  
21  import java.io.Serializable;
22  import java.util.logging.Logger;
23  
24  import javax.el.ValueExpression;
25  import javax.faces.FacesException;
26  import javax.faces.component.UIViewRoot;
27  import javax.faces.context.FacesContext;
28  import javax.faces.event.AbortProcessingException;
29  import javax.faces.event.PhaseEvent;
30  import javax.faces.event.PhaseId;
31  import javax.faces.event.PhaseListener;
32  import javax.faces.webapp.UIComponentELTag;
33  import javax.servlet.jsp.JspException;
34  import javax.servlet.jsp.tagext.Tag;
35  import javax.servlet.jsp.tagext.TagSupport;
36  
37  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspAttribute;
38  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspTag;
39  import org.apache.myfaces.shared.util.ClassUtils;
40  
41  /**
42   * Register a PhaseListener instance
43   * 
44   * @author martin.haimberger
45   * @version $Revision$ $Date$
46   */
47  @JSFJspTag(name = "f:phaseListener", bodyContent = "empty")
48  public class PhaseListenerTag extends TagSupport
49  {
50      
51      private static final Logger log = Logger.getLogger(PhaseListenerTag.class.getName());
52      
53      /**
54       * The fully qualified class name of the PhaseListener which should be created.
55       */
56      private ValueExpression type = null;
57  
58      /**
59       * A value binding expression used to create a PhaseListener instance.
60       */
61      private ValueExpression binding = null;
62  
63      /**
64       * Class name of the PhaseListener to be created and registered.
65       */
66      @JSFJspAttribute(className="javax.el.ValueExpression",
67              deferredValueType="java.lang.String")
68      public void setType(ValueExpression type)
69      {
70          this.type = type;
71      }
72  
73      /**
74       * Value binding expression that evaluates to a PhaseListener.
75       */
76      @JSFJspAttribute(className="javax.el.ValueExpression",
77              deferredValueType="javax.faces.event.PhaseListener")
78      public void setBinding(ValueExpression binding)
79      {
80          this.binding = binding;
81      }
82  
83      @Override
84      public int doStartTag() throws JspException
85      {
86  
87          // JSF-Spec 1.2 9.4.9
88          // Locate the one and only UIViewRoot custom action instance by walking up the tag tree
89          // until you find a UIComponentELTag instance that has no parent. If the
90          // getCreated() method of this instance returns true, check the binding attribute.
91  
92          Tag parent = this;
93          UIComponentELTag parentTag = null;
94          while ((parent = parent.getParent()) != null)
95          {
96              if (parent instanceof UIComponentELTag)
97              {
98                  parentTag = (UIComponentELTag)parent;
99              }
100         }
101 
102         if (parentTag == null)
103         {
104             throw new JspException("Not nested in a UIViewRoot Error for tag with handler class: "
105                     + this.getClass().getName());
106         }
107 
108         if (!parentTag.getCreated())
109         {
110             return SKIP_BODY;
111         }
112 
113         UIViewRoot root = (UIViewRoot)parentTag.getComponentInstance();
114 
115         // JSF-Spec 1.2 9.4.9
116         // If binding is set, call binding.getValue() to obtain a reference to the
117         // PhaseListener instance. If there is no exception thrown, and binding.getValue()
118         // returned a non-null object that implements javax.faces.event.PhaseListener, register
119         // it by calling addPhaseListener(). If there was an exception thrown, rethrow the
120         // exception as a JspException.
121 
122         // If the listener instance could not be created, check the type attribute. If the type
123         // attribute is set, instantiate an instance of the specified class, and register it by calling
124         // addPhaseListener(). If the binding attribute was also set, store the listener instance
125         // by calling binding.setValue(). If there was an exception thrown, rethrow the
126         // exception as a JspException.
127 
128         PhaseListener listener = null;
129         try
130         {
131             listener = new BindingPhaseListener(binding, type);
132         }
133         catch (Exception ex)
134         {
135             throw new JspException(ex.getMessage(), ex);
136         }
137 
138         root.addPhaseListener(listener);
139 
140         return SKIP_BODY;
141 
142     }
143 
144     private static class BindingPhaseListener implements PhaseListener, Serializable
145     {
146 
147         private transient PhaseListener phaseListenerCache = null;
148         private ValueExpression type;
149         private ValueExpression binding;
150         //private final Log log = LogFactory.getLog(PhaseListenerTag.class);
151 
152         BindingPhaseListener(ValueExpression binding, ValueExpression type)
153         {
154             this.binding = binding;
155             this.type = type;
156         }
157 
158         public void afterPhase(PhaseEvent event)
159         {
160             PhaseListener listener = getPhaseListener();
161             if (listener != null)
162             {
163                 listener.afterPhase(event);
164             }
165         }
166 
167         public void beforePhase(PhaseEvent event)
168         {
169             PhaseListener listener = getPhaseListener();
170             if (listener != null)
171             {
172                 listener.beforePhase(event);
173             }
174         }
175 
176         public PhaseId getPhaseId()
177         {
178             PhaseListener listener = getPhaseListener();
179             if (listener != null)
180             {
181                 return listener.getPhaseId();
182             }
183 
184             return null;
185 
186         }
187 
188         private PhaseListener getPhaseListener()
189         {
190 
191             if (phaseListenerCache != null)
192             {
193                 return phaseListenerCache;
194             }
195             else
196             {
197                 // create PhaseListenerInstance
198                 phaseListenerCache = getPhaseListnerInstance(binding, type);
199             }
200             if (phaseListenerCache == null)
201             {
202                 log.warning("PhaseListener will not be installed. Both binding and type are null.");
203 
204             }
205 
206             return phaseListenerCache;
207 
208         }
209 
210         private PhaseListener getPhaseListnerInstance(ValueExpression binding, ValueExpression type)
211         {
212             FacesContext currentFacesContext = FacesContext.getCurrentInstance();
213             Object phasesInstance = null;
214             if (binding != null)
215             {
216                 phasesInstance = binding.getValue(currentFacesContext.getELContext());
217             }
218             else if (type != null)
219             {
220                 try
221                 {
222                     phasesInstance = ClassUtils.newInstance((String)type.getValue(currentFacesContext.getELContext()));
223                 }
224                 catch (FacesException ex)
225                 {
226                     throw new AbortProcessingException(ex.getMessage(), ex);
227                 }
228             }
229             return (PhaseListener)phasesInstance;
230 
231         }
232 
233     }
234 }