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.updateactionlistener;
20  
21  import javax.faces.FacesException;
22  import javax.faces.component.StateHolder;
23  import javax.faces.component.UIComponentBase;
24  import javax.faces.component.ValueHolder;
25  import javax.faces.context.FacesContext;
26  import javax.faces.convert.Converter;
27  import javax.faces.el.ValueBinding;
28  import javax.faces.event.AbortProcessingException;
29  import javax.faces.event.ActionEvent;
30  import javax.faces.event.ActionListener;
31  
32  /**
33   * Set an arbitrary property on a managed bean when an "action" component is
34   * selected by the user.
35   * <p>
36   * An instance of this listener type can be attached to any UIComponent which
37   * is an ActionSource (eg a link or button). When the associated component
38   * fires its action event, this listener will read the value specified by
39   * attribute "value" and assign it to the property specified by attribute
40   * "property". The value attribute may be a literal value or may be a
41   * value-binding; the property is always expected to be a value-binding.
42   * <p>
43   * An optional Converter may be associated with this listener, and if present
44   * will be invoked to convert the value to the datatype expected by the
45   * target property. When no converter is available, a default one will be
46   * retrieved from the Application object.
47   * <p>
48   * A common use for this listener is to attach it to an HtmlCommandLink
49   * component, storing some constant value into a managed bean property.
50   * After the navigation associated with that link is done, components in
51   * the new view can look at that property to determine which link was
52   * clicked.
53   * <p>
54   * Both the fetching of "value" and the updating of "property" occur in
55   * the invoke-application phase unless "immediate" is set on the ActionSource
56   * component in which case they both occur in the apply-request-values phase.
57   * The update is guaranteed to occur before the invocation of the method
58   * specified by attribute "action" on the ActionSource (because all
59   * actionListeners are executed before the action attribute).
60   * <p>
61   * JSF 1.2 introduces a "setPropertyActionListener" with the same functionality like this.
62   * <p>
63   * @author Manfred Geiler (latest modification by $Author: grantsmith $)
64   * @version $Revision: 472638 $ $Date: 2006-11-08 15:54:13 -0500 (Wed, 08 Nov 2006) $
65   */
66  public class UpdateActionListener
67          implements ActionListener, ValueHolder, StateHolder
68  {
69      //private static final Log log = LogFactory.getLog(UpdateActionListener.class);
70  
71      private ValueBinding _propertyBinding;
72      private Object _value;
73      private ValueBinding _valueBinding;
74      private Converter _converter;
75  
76      public void setPropertyBinding(ValueBinding propertyBinding)
77      {
78          _propertyBinding = propertyBinding;
79      }
80  
81      public ValueBinding getPropertyBinding()
82      {
83          return _propertyBinding;
84      }
85  
86      public void setValue(Object value)
87      {
88          _value = value;
89      }
90  
91      public Object getValue()
92      {
93          if (_value != null) return _value;
94          ValueBinding vb = getValueBinding();
95          if (vb != null)
96          {
97              FacesContext context = FacesContext.getCurrentInstance();
98              return vb.getValue(context);
99          }
100         return null;
101     }
102 
103     public Object getLocalValue()
104     {
105         return _value;
106     }
107 
108     public ValueBinding getValueBinding()
109     {
110         return _valueBinding;
111     }
112 
113     public void setValueBinding(ValueBinding valueBinding)
114     {
115         _valueBinding = valueBinding;
116     }
117 
118     public Converter getConverter()
119     {
120         return _converter;
121     }
122 
123     public void setConverter(Converter converter)
124     {
125         _converter = converter;
126     }
127 
128     public void processAction(ActionEvent actionEvent) throws AbortProcessingException
129     {
130         FacesContext context = FacesContext.getCurrentInstance();
131         ValueBinding updateBinding = getPropertyBinding();
132         Object v = getValue();
133         if (v != null &&
134             v instanceof String)
135         {
136             Class type = updateBinding.getType(context);
137             if (!type.equals(String.class) && ! type.equals(Object.class))
138             {
139                 String converterErrorMessage = "No Converter registered with UpdateActionListener and no appropriate standard converter found. Needed to convert String to " + type.getName();
140                 Converter converter = getConverter();
141                 if (converter == null)
142                 {
143                     try
144                     {
145                         converter = context.getApplication().createConverter(type);
146                     }
147                     catch (Exception e)
148                     {
149                         throw new FacesException(converterErrorMessage, e);
150                     }
151                 }
152                 if (null == converter)
153                 {
154                     throw new FacesException(converterErrorMessage);
155                 }
156                 v = converter.getAsObject(context, context.getViewRoot(), (String)v);
157             }
158         }
159         updateBinding.setValue(context, v);
160     }
161 
162 
163 
164     // StateHolder methods
165 
166     public Object saveState(FacesContext context)
167     {
168         Object values[] = new Object[4];
169         values[0] = UIComponentBase.saveAttachedState(context, _propertyBinding);
170         values[1] = _value;
171         values[2] = UIComponentBase.saveAttachedState(context, _valueBinding);
172         values[3] = UIComponentBase.saveAttachedState(context, _converter);
173         return ((Object) (values));
174     }
175 
176     public void restoreState(FacesContext context, Object state)
177     {
178         Object values[] = (Object[])state;
179         _propertyBinding = (ValueBinding)UIComponentBase.restoreAttachedState(context, values[0]);
180         _value = values[1];
181         _valueBinding = (ValueBinding)UIComponentBase.restoreAttachedState(context, values[2]);;
182         _converter = (Converter)UIComponentBase.restoreAttachedState(context, values[3]);;
183     }
184 
185     public boolean isTransient()
186     {
187         return false;
188     }
189 
190     public void setTransient(boolean newTransientValue)
191     {
192         if (newTransientValue == true) throw new IllegalArgumentException();
193     }
194 
195 }