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.commons.validator;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.Map;
28  
29  import javax.faces.application.FacesMessage;
30  import javax.faces.component.StateHolder;
31  import javax.faces.context.FacesContext;
32  import javax.faces.el.ValueBinding;
33  import javax.faces.validator.Validator;
34  
35  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
36  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator;
37  import org.apache.myfaces.commons.util.MessageUtils;
38  
39  /**
40   * Base validator implementation for Apache MyFaces Commons Validators.
41   *
42   */
43  @JSFValidator(
44     configExcluded = true,
45     evaluateELOnExecution = true,
46     tagClass = "org.apache.myfaces.commons.validator.ValidatorBaseTag",
47     tagHandler = "org.apache.myfaces.commons.validator.ValidatorBaseTagHandler")
48  public abstract class ValidatorBase implements StateHolder, Validator {
49  
50      private String _summaryMessage = null;
51      private String _detailMessage = null;
52      private boolean _transient = false;
53  
54      /**
55       * alternate validation error summary message format string
56       * 
57       * @return  The summary message to be displayed
58       */
59      @JSFProperty
60      public String getSummaryMessage()
61      {
62          if (_summaryMessage != null) return _summaryMessage;
63          ValueBinding vb = getValueBinding("summaryMessage");
64          return vb != null ? getStringValue(getFacesContext(), vb) : null;
65      }
66  
67      /**
68       *
69       * @param message   The summary message to be displayed.
70       */
71      public void setSummaryMessage(String message) {
72          _summaryMessage = message;
73      }
74  
75      /**
76       * alternate validation error detail message format string 
77       * (use 'message' and 'detailMessage' alternatively)
78       * 
79       * @return  The message.
80       * @deprecated Use getDetailMessage()
81       */
82      @JSFProperty
83      public String getMessage() {
84          return getDetailMessage();
85      }
86  
87      /**
88       *
89       * @param message  The detail message to be displayed.
90       * @deprecated Use setDetailMessage()
91       */
92      public void setMessage(String message) {
93          setDetailMessage(message);
94      }
95  
96  
97      /**
98       * alternate validation error detail message format string 
99       * (use 'message' and 'detailMessage' alternatively)
100      *
101      * @return  The detail message.
102      */
103     @JSFProperty
104     public String getDetailMessage() {
105         if (_detailMessage != null) return _detailMessage;
106         ValueBinding vb = getValueBinding("detailMessage");
107         return vb != null ? getStringValue(getFacesContext(), vb) : null;
108     }
109 
110     /**
111      *
112      * @param message  The detail message to be displayed.
113      */
114     public void setDetailMessage(String message) {
115         _detailMessage = message;
116     }
117 
118 
119     /**
120      * @param context
121      */
122     public Object saveState(FacesContext context) {
123         Object[] state = new Object[3];
124         state[0] = _summaryMessage;
125         state[1] = _detailMessage;
126         state[2] = saveValueBindingMap(context);
127         return state;
128     }
129 
130     public void restoreState(FacesContext context, Object state) {
131         Object[] values = (Object[]) state;
132         _summaryMessage = (String) values[0];
133         _detailMessage = (String) values[1];
134         restoreValueBindingMap(context, values[2]);
135     }
136 
137     public boolean isTransient() {
138         return _transient;
139     }
140 
141     public void setTransient(boolean newTransientValue) {
142         _transient = newTransientValue;
143     }
144 
145     // Utility methods
146 
147     /**
148      * @param defaultMessage The default message we would expect.
149      * @param args Arguments for parsing this message.
150      * @return FacesMessage
151      */
152     protected FacesMessage getFacesMessage(String defaultMessage, Object[] args) {
153         FacesMessage msg;
154 
155         if (getSummaryMessage() == null && getDetailMessage() == null)
156         {
157             msg = MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, defaultMessage, args);
158         } else {
159             Locale locale = MessageUtils.getCurrentLocale();
160             String summaryText = MessageUtils.substituteParams(locale, getSummaryMessage(), args);
161             String detailText = MessageUtils.substituteParams(locale, getDetailMessage(), args);
162             msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, summaryText, detailText);
163         }
164         return msg;
165     }
166 
167     // --------------------- borrowed from UIComponentBase ------------
168 
169     private Map _valueBindingMap = null;
170 
171     public ValueBinding getValueBinding(String name)
172     {
173         if (name == null) throw new NullPointerException("name");
174         if (_valueBindingMap == null)
175         {
176             return null;
177         }
178         else
179         {
180             return (ValueBinding)_valueBindingMap.get(name);
181         }
182     }
183 
184     public void setValueBinding(String name,
185                                 ValueBinding binding)
186     {
187         if (name == null) throw new NullPointerException("name");
188         if (_valueBindingMap == null)
189         {
190             _valueBindingMap = new HashMap();
191         }
192         _valueBindingMap.put(name, binding);
193     }
194 
195     private Object saveValueBindingMap(FacesContext context)
196     {
197         if (_valueBindingMap != null)
198         {
199             int initCapacity = (_valueBindingMap.size() * 4 + 3) / 3;
200             HashMap stateMap = new HashMap(initCapacity);
201             for (Iterator it = _valueBindingMap.entrySet().iterator(); it.hasNext(); )
202             {
203                 Map.Entry entry = (Map.Entry)it.next();
204                 stateMap.put(entry.getKey(),
205                              saveAttachedState(context, entry.getValue()));
206             }
207             return stateMap;
208         }
209         else
210         {
211             return null;
212         }
213     }
214 
215     private void restoreValueBindingMap(FacesContext context, Object stateObj)
216     {
217         if (stateObj != null)
218         {
219             Map stateMap = (Map)stateObj;
220             int initCapacity = (stateMap.size() * 4 + 3) / 3;
221             _valueBindingMap = new HashMap(initCapacity);
222             for (Iterator it = stateMap.entrySet().iterator(); it.hasNext(); )
223             {
224                 Map.Entry entry = (Map.Entry)it.next();
225                 _valueBindingMap.put(entry.getKey(),
226                                      restoreAttachedState(context, entry.getValue()));
227             }
228         }
229         else
230         {
231             _valueBindingMap = null;
232         }
233     }
234 
235     /**
236      * Serializes objects which are "attached" to this component but which are
237      * not UIComponent children of it. Examples are validator and listener
238      * objects. To be precise, it returns an object which implements
239      * java.io.Serializable, and which when serialized will persist the
240      * state of the provided object.
241      * <p>
242      * If the attachedObject is a List then every object in the list is saved
243      * via a call to this method, and the returned wrapper object contains
244      * a List object.
245      * <p>
246      * If the object implements StateHolder then the object's saveState is
247      * called immediately, and a wrapper is returned which contains both
248      * this saved state and the original class name. However in the case
249      * where the StateHolder.isTransient method returns true, null is
250      * returned instead.
251      * <p>
252      * If the object implements java.io.Serializable then the object is simply
253      * returned immediately; standard java serialization will later be used
254      * to store this object.
255      * <p>
256      * In all other cases, a wrapper is returned which simply stores the type
257      * of the provided object. When deserialized, a default instance of that
258      * type will be recreated.
259      */
260     public static Object saveAttachedState(FacesContext context,
261                                            Object attachedObject)
262     {
263         if (attachedObject == null) return null;
264         if (attachedObject instanceof List)
265         {
266             List lst = new ArrayList(((List)attachedObject).size());
267             for (Iterator it = ((List)attachedObject).iterator(); it.hasNext(); )
268             {
269                 lst.add(saveAttachedState(context, it.next()));
270             }
271             return new _AttachedListStateWrapper(lst);
272         }
273         else if (attachedObject instanceof StateHolder)
274         {
275             if (((StateHolder)attachedObject).isTransient())
276             {
277                 return null;
278             }
279             else
280             {
281                 return new _AttachedStateWrapper(attachedObject.getClass(),
282                                                  ((StateHolder)attachedObject).saveState(context));
283             }
284         }
285         else if (attachedObject instanceof Serializable)
286         {
287             return attachedObject;
288         }
289         else
290         {
291             return new _AttachedStateWrapper(attachedObject.getClass(), null);
292         }
293     }
294 
295     public static Object restoreAttachedState(FacesContext context,
296                                               Object stateObj)
297             throws IllegalStateException
298     {
299         if (context == null) throw new NullPointerException("context");
300         if (stateObj == null) return null;
301         if (stateObj instanceof _AttachedListStateWrapper)
302         {
303             List lst = ((_AttachedListStateWrapper)stateObj).getWrappedStateList();
304             List restoredList = new ArrayList(lst.size());
305             for (Iterator it = lst.iterator(); it.hasNext(); )
306             {
307                 restoredList.add(restoreAttachedState(context, it.next()));
308             }
309             return restoredList;
310         }
311         else if (stateObj instanceof _AttachedStateWrapper)
312         {
313             Class clazz = ((_AttachedStateWrapper)stateObj).getClazz();
314             Object restoredObject;
315             try
316             {
317                 restoredObject = clazz.newInstance();
318             }
319             catch (InstantiationException e)
320             {
321                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName() + " (missing no-args constructor?)", e);
322             }
323             catch (IllegalAccessException e)
324             {
325                 throw new RuntimeException(e);
326             }
327             if (restoredObject instanceof StateHolder)
328             {
329                 Object wrappedState = ((_AttachedStateWrapper)stateObj).getWrappedStateObject();
330                 ((StateHolder)restoredObject).restoreState(context, wrappedState);
331             }
332             return restoredObject;
333         }
334         else
335         {
336             return stateObj;
337         }
338     }
339 
340 
341     protected FacesContext getFacesContext()
342     {
343         return FacesContext.getCurrentInstance();
344     }
345     protected String getStringValue(FacesContext context, ValueBinding vb)
346     {
347         Object value = vb.getValue(context);
348         if (value != null)
349         {
350             return value.toString();
351         }
352         return null;
353     }
354 }