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.List;
24  import java.util.Locale;
25  import java.util.Map;
26  
27  import javax.el.ValueExpression;
28  import javax.faces.application.FacesMessage;
29  import javax.faces.component.PartialStateHolder;
30  import javax.faces.component.StateHelper;
31  import javax.faces.component.StateHolder;
32  import javax.faces.context.FacesContext;
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 PartialStateHolder, Validator {
49  
50      private boolean _transient = false;
51      
52      private transient FacesContext _facesContext;
53      private StateHelper _stateHelper = null;
54      private boolean _initialStateMarked = false;
55  
56      /**
57       * alternate validation error summary message format string
58       * 
59       * @return  The summary message to be displayed
60       */
61      @JSFProperty
62      public String getSummaryMessage()
63      {
64          return (String) getStateHelper().eval(PropertyKeys.summaryMessage);
65      }
66  
67      /**
68       *
69       * @param message   The summary message to be displayed.
70       */
71      public void setSummaryMessage(String message) {
72          getStateHelper().put(PropertyKeys.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         return (String) getStateHelper().eval(PropertyKeys.detailMessage);
106     }
107 
108     /**
109      *
110      * @param message  The detail message to be displayed.
111      */
112     public void setDetailMessage(String message) {
113         getStateHelper().put(PropertyKeys.detailMessage, message);
114     }
115 
116 
117     /**
118      * @param context
119      */
120     public Object saveState(FacesContext context)
121     {
122         if (context == null)
123         {
124             throw new NullPointerException ("context");
125         }
126         
127         StateHelper stateHelper = getStateHelper(false);
128         if (stateHelper != null)
129         {
130             return stateHelper.saveState(context);
131         }
132         else
133         {
134             return null;
135         }
136     }
137 
138     public void restoreState(FacesContext context, Object state)
139     {
140         getStateHelper().restoreState(context, state);
141     }
142 
143     public boolean isTransient() {
144         return _transient;
145     }
146 
147     public void setTransient(boolean newTransientValue) {
148         _transient = newTransientValue;
149     }
150 
151     // Utility methods
152 
153     /**
154      * @param defaultMessage The default message we would expect.
155      * @param args Arguments for parsing this message.
156      * @return FacesMessage
157      */
158     protected FacesMessage getFacesMessage(String defaultMessage, Object[] args) {
159         FacesMessage msg;
160 
161         if (getSummaryMessage() == null && getDetailMessage() == null)
162         {
163             msg = MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, defaultMessage, args);
164         } else {
165             Locale locale = MessageUtils.getCurrentLocale();
166             String summaryText = MessageUtils.substituteParams(locale, getSummaryMessage(), args);
167             String detailText = MessageUtils.substituteParams(locale, getDetailMessage(), args);
168             msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, summaryText, detailText);
169         }
170         return msg;
171     }
172 
173     // --------------------- borrowed from UIComponentBase ------------
174 
175     @SuppressWarnings("unchecked")
176     public ValueExpression getValueExpression(String name)
177     {
178         if (name == null) throw new NullPointerException("name");
179         StateHelper helper = getStateHelper(false);
180         if (helper == null)
181         {
182             return null;
183         }
184         Map<String,Object> bindings = (Map<String,Object>) helper.get(PropertyKeys.bindings); 
185         if (bindings == null)
186         {
187             return null;
188         }
189         else
190         {
191             return (ValueExpression) bindings.get(name);
192         }
193     }
194     
195     public void setValueExpression(String name, ValueExpression expression)
196     {
197         if (name == null) throw new NullPointerException("name");
198         if (expression == null) {
199             getStateHelper().remove(PropertyKeys.bindings, name);
200         } else {
201             getStateHelper().put(PropertyKeys.bindings, name, expression);
202         }
203     }
204 
205     /**
206      * Serializes objects which are "attached" to this component but which are
207      * not UIComponent children of it. Examples are validator and listener
208      * objects. To be precise, it returns an object which implements
209      * java.io.Serializable, and which when serialized will persist the
210      * state of the provided object.
211      * <p>
212      * If the attachedObject is a List then every object in the list is saved
213      * via a call to this method, and the returned wrapper object contains
214      * a List object.
215      * <p>
216      * If the object implements StateHolder then the object's saveState is
217      * called immediately, and a wrapper is returned which contains both
218      * this saved state and the original class name. However in the case
219      * where the StateHolder.isTransient method returns true, null is
220      * returned instead.
221      * <p>
222      * If the object implements java.io.Serializable then the object is simply
223      * returned immediately; standard java serialization will later be used
224      * to store this object.
225      * <p>
226      * In all other cases, a wrapper is returned which simply stores the type
227      * of the provided object. When deserialized, a default instance of that
228      * type will be recreated.
229      */
230     public static Object saveAttachedState(FacesContext context, Object attachedObject)
231     {
232         if (context == null)
233         {
234             throw new NullPointerException ("context");
235         }
236         
237         if (attachedObject == null)
238             return null;
239         // StateHolder interface should take precedence over
240         // List children
241         if (attachedObject instanceof StateHolder)
242         {
243             StateHolder holder = (StateHolder) attachedObject;
244             if (holder.isTransient())
245             {
246                 return null;
247             }
248 
249             return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
250         }        
251         else if (attachedObject instanceof List)
252         {
253             List<Object> lst = new ArrayList<Object>(((List<?>) attachedObject).size());
254             for (Object item : (List<?>) attachedObject)
255             {
256                 if (item != null)
257                 {
258                     lst.add(saveAttachedState(context, item));
259                 }
260             }
261 
262             return new _AttachedListStateWrapper(lst);
263         }
264         else if (attachedObject instanceof Serializable)
265         {
266             return attachedObject;
267         }
268         else
269         {
270             return new _AttachedStateWrapper(attachedObject.getClass(), null);
271         }
272     }
273 
274     @SuppressWarnings("unchecked")
275     public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
276     {
277         if (context == null)
278             throw new NullPointerException("context");
279         if (stateObj == null)
280             return null;
281         if (stateObj instanceof _AttachedListStateWrapper)
282         {
283             List<Object> lst = ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
284             List<Object> restoredList = new ArrayList<Object>(lst.size());
285             for (Object item : lst)
286             {
287                 restoredList.add(restoreAttachedState(context, item));
288             }
289             return restoredList;
290         }
291         else if (stateObj instanceof _AttachedStateWrapper)
292         {
293             Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
294             Object restoredObject;
295             try
296             {
297                 restoredObject = clazz.newInstance();
298             }
299             catch (InstantiationException e)
300             {
301                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
302                         + " (missing no-args constructor?)", e);
303             }
304             catch (IllegalAccessException e)
305             {
306                 throw new RuntimeException(e);
307             }
308             if (restoredObject instanceof StateHolder)
309             {
310                 _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
311                 Object wrappedState = wrapper.getWrappedStateObject();
312 
313                 StateHolder holder = (StateHolder) restoredObject;
314                 holder.restoreState(context, wrappedState);
315             }
316             return restoredObject;
317         }
318         else
319         {
320             return stateObj;
321         }
322     }
323 
324     protected FacesContext getFacesContext()
325     {
326         if (_facesContext == null)
327         {
328             return FacesContext.getCurrentInstance();
329         }
330         else
331         {
332             return _facesContext;
333         }
334     }
335     
336     boolean isCachedFacesContext()
337     {
338         return _facesContext != null;
339     }
340     
341     void setCachedFacesContext(FacesContext facesContext)
342     {
343         _facesContext = facesContext;
344     }
345     
346     protected StateHelper getStateHelper() {
347         return getStateHelper(true);
348     }
349 
350     /**
351      * returns a delta state saving enabled state helper
352      * for the current component
353      * @param create if true a state helper is created if not already existing
354      * @return an implementation of the StateHelper interface or null if none exists and create is set to false
355      */
356     protected StateHelper getStateHelper(boolean create) {
357         if(_stateHelper != null) {
358             return _stateHelper;
359         }
360         if(create) {
361             _stateHelper = new _DeltaStateHelper(this);
362         }
363         return _stateHelper;
364     }
365     
366     public void clearInitialState()
367     {
368         _initialStateMarked = false;
369     }
370 
371     public boolean initialStateMarked()
372     {
373         return _initialStateMarked;
374     }
375 
376     public void markInitialState()
377     {
378         _initialStateMarked = true;
379     }
380 
381     protected String getStringValue(FacesContext context, ValueExpression vb)
382     {
383         Object value = vb.getValue(context.getELContext());
384         if (value != null)
385         {
386             return value.toString();
387         }
388         return null;
389     }
390     
391     enum PropertyKeys
392     {
393         bindings,
394         summaryMessage,
395         detailMessage
396     }
397 }