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