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.converter;
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.convert.Converter;
34  
35  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
36  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
37  import org.apache.myfaces.commons.util.MessageUtils;
38  
39  /**
40   * Base converter implementation for Apache MyFaces Commons Converters.
41   *
42   */
43  @JSFConverter(
44     configExcluded = true,
45     evaluateELOnExecution = true,
46     tagClass = "org.apache.myfaces.commons.converter.ConverterBaseTag",
47     tagHandler = "org.apache.myfaces.commons.converter.ConverterBaseTagHandler")
48  public abstract class ConverterBase implements PartialStateHolder, Converter {
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 conversion 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 conversion error detail message format string 
77       * (use 'message' and 'detailMessage' alternatively)
78       *
79       * @return  The detail message.
80       */
81      @JSFProperty
82      public String getDetailMessage() {
83          return (String) getStateHelper().eval(PropertyKeys.detailMessage);
84      }
85  
86      /**
87       *
88       * @param message  The detail message to be displayed.
89       */
90      public void setDetailMessage(String message) {
91          getStateHelper().put(PropertyKeys.detailMessage, message);
92      }
93  
94  
95      /**
96       * @param context
97       */
98      public Object saveState(FacesContext context)
99      {
100         if (context == null)
101         {
102             throw new NullPointerException ("context");
103         }
104         
105         StateHelper stateHelper = getStateHelper(false);
106         if (stateHelper != null)
107         {
108             return stateHelper.saveState(context);
109         }
110         else
111         {
112             return null;
113         }
114     }
115 
116     public void restoreState(FacesContext context, Object state)
117     {
118         getStateHelper().restoreState(context, state);
119     }
120 
121     public boolean isTransient() {
122         return _transient;
123     }
124 
125     public void setTransient(boolean newTransientValue) {
126         _transient = newTransientValue;
127     }
128 
129     // Utility methods
130 
131     /**
132      * @param defaultMessage The default message we would expect.
133      * @param args Arguments for parsing this message.
134      * @return FacesMessage
135      */
136     protected FacesMessage getFacesMessage(String defaultMessage, Object[] args) {
137         FacesMessage msg;
138 
139         if (getSummaryMessage() == null && getDetailMessage() == null)
140         {
141             msg = MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR, defaultMessage, args);
142         } else {
143             Locale locale = MessageUtils.getCurrentLocale();
144             String summaryText = MessageUtils.substituteParams(locale, getSummaryMessage(), args);
145             String detailText = MessageUtils.substituteParams(locale, getDetailMessage(), args);
146             msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, summaryText, detailText);
147         }
148         return msg;
149     }
150 
151     // --------------------- borrowed from UIComponentBase ------------
152 
153     @SuppressWarnings("unchecked")
154     public ValueExpression getValueExpression(String name)
155     {
156         if (name == null) throw new NullPointerException("name");
157         StateHelper helper = getStateHelper(false);
158         if (helper == null)
159         {
160             return null;
161         }
162         Map<String,Object> bindings = (Map<String,Object>) helper.get(PropertyKeys.bindings); 
163         if (bindings == null)
164         {
165             return null;
166         }
167         else
168         {
169             return (ValueExpression) bindings.get(name);
170         }
171     }
172     
173     public void setValueExpression(String name, ValueExpression expression)
174     {
175         if (name == null) throw new NullPointerException("name");
176         if (expression == null) {
177             getStateHelper().remove(PropertyKeys.bindings, name);
178         } else {
179             getStateHelper().put(PropertyKeys.bindings, name, expression);
180         }
181     }
182 
183     /**
184      * Serializes objects which are "attached" to this component but which are
185      * not UIComponent children of it. Examples are converter and listener
186      * objects. To be precise, it returns an object which implements
187      * java.io.Serializable, and which when serialized will persist the
188      * state of the provided object.
189      * <p>
190      * If the attachedObject is a List then every object in the list is saved
191      * via a call to this method, and the returned wrapper object contains
192      * a List object.
193      * <p>
194      * If the object implements StateHolder then the object's saveState is
195      * called immediately, and a wrapper is returned which contains both
196      * this saved state and the original class name. However in the case
197      * where the StateHolder.isTransient method returns true, null is
198      * returned instead.
199      * <p>
200      * If the object implements java.io.Serializable then the object is simply
201      * returned immediately; standard java serialization will later be used
202      * to store this object.
203      * <p>
204      * In all other cases, a wrapper is returned which simply stores the type
205      * of the provided object. When deserialized, a default instance of that
206      * type will be recreated.
207      */
208     public static Object saveAttachedState(FacesContext context, Object attachedObject)
209     {
210         if (context == null)
211         {
212             throw new NullPointerException ("context");
213         }
214         
215         if (attachedObject == null)
216             return null;
217         // StateHolder interface should take precedence over
218         // List children
219         if (attachedObject instanceof StateHolder)
220         {
221             StateHolder holder = (StateHolder) attachedObject;
222             if (holder.isTransient())
223             {
224                 return null;
225             }
226 
227             return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
228         }        
229         else if (attachedObject instanceof List)
230         {
231             List<Object> lst = new ArrayList<Object>(((List<?>) attachedObject).size());
232             for (Object item : (List<?>) attachedObject)
233             {
234                 if (item != null)
235                 {
236                     lst.add(saveAttachedState(context, item));
237                 }
238             }
239 
240             return new _AttachedListStateWrapper(lst);
241         }
242         else if (attachedObject instanceof Serializable)
243         {
244             return attachedObject;
245         }
246         else
247         {
248             return new _AttachedStateWrapper(attachedObject.getClass(), null);
249         }
250     }
251 
252     @SuppressWarnings("unchecked")
253     public static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
254     {
255         if (context == null)
256             throw new NullPointerException("context");
257         if (stateObj == null)
258             return null;
259         if (stateObj instanceof _AttachedListStateWrapper)
260         {
261             List<Object> lst = ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
262             List<Object> restoredList = new ArrayList<Object>(lst.size());
263             for (Object item : lst)
264             {
265                 restoredList.add(restoreAttachedState(context, item));
266             }
267             return restoredList;
268         }
269         else if (stateObj instanceof _AttachedStateWrapper)
270         {
271             Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
272             Object restoredObject;
273             try
274             {
275                 restoredObject = clazz.newInstance();
276             }
277             catch (InstantiationException e)
278             {
279                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
280                         + " (missing no-args constructor?)", e);
281             }
282             catch (IllegalAccessException e)
283             {
284                 throw new RuntimeException(e);
285             }
286             if (restoredObject instanceof StateHolder)
287             {
288                 _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
289                 Object wrappedState = wrapper.getWrappedStateObject();
290 
291                 StateHolder holder = (StateHolder) restoredObject;
292                 holder.restoreState(context, wrappedState);
293             }
294             return restoredObject;
295         }
296         else
297         {
298             return stateObj;
299         }
300     }
301 
302     protected FacesContext getFacesContext()
303     {
304         if (_facesContext == null)
305         {
306             return FacesContext.getCurrentInstance();
307         }
308         else
309         {
310             return _facesContext;
311         }
312     }
313     
314     boolean isCachedFacesContext()
315     {
316         return _facesContext != null;
317     }
318     
319     void setCachedFacesContext(FacesContext facesContext)
320     {
321         _facesContext = facesContext;
322     }
323     
324     protected StateHelper getStateHelper() {
325         return getStateHelper(true);
326     }
327 
328     /**
329      * returns a delta state saving enabled state helper
330      * for the current component
331      * @param create if true a state helper is created if not already existing
332      * @return an implementation of the StateHelper interface or null if none exists and create is set to false
333      */
334     protected StateHelper getStateHelper(boolean create) {
335         if(_stateHelper != null) {
336             return _stateHelper;
337         }
338         if(create) {
339             _stateHelper = new _DeltaStateHelper(this);
340         }
341         return _stateHelper;
342     }
343     
344     public void clearInitialState()
345     {
346         _initialStateMarked = false;
347     }
348 
349     public boolean initialStateMarked()
350     {
351         return _initialStateMarked;
352     }
353 
354     public void markInitialState()
355     {
356         _initialStateMarked = true;
357     }
358 
359     protected String getStringValue(FacesContext context, ValueExpression vb)
360     {
361         Object value = vb.getValue(context.getELContext());
362         if (value != null)
363         {
364             return value.toString();
365         }
366         return null;
367     }
368     
369     enum PropertyKeys
370     {
371         bindings,
372         summaryMessage,
373         detailMessage
374     }
375 }