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