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 javax.faces.application.FacesMessage;
22  import javax.faces.component.PartialStateHolder;
23  import javax.faces.component.UIComponent;
24  import javax.faces.context.FacesContext;
25  import javax.faces.convert.Converter;
26  import javax.faces.convert.ConverterException;
27  
28  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
29  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
30  import org.apache.myfaces.commons.util.MessageUtils;
31  
32  /**
33   * Converts a Java 5 Enum.
34   * 
35   * see Javadoc of <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
36   *
37   *   
38   * @author Stan Silvert
39   */
40  @JSFConverter(
41     name = "mcc:convertEnum",
42     tagClass = "org.apache.myfaces.commons.converter.ConvertEnumTag",
43     tagHandler = "org.apache.myfaces.commons.converter.ConvertEnumTagHandler",
44     serialuidtag = "3864584277821896141L")
45  public class EnumConverter implements Converter, PartialStateHolder {
46      
47      public static final String CONVERTER_ID = "org.apache.myfaces.commons.converter.Enum";
48      public static final String ENUM_ID = "org.apache.myfaces.commons.converter.EnumConverter.ENUM";
49      public static final String ENUM_NO_CLASS_ID = "org.apache.myfaces.commons.converter.EnumConverter.ENUM_NO_CLASS";
50      public static final String ENUM_NO_ENUM_CLASS = "org.apache.myfaces.commons.converter.EnumConverter.ENUM_NO_ENUM_CLASS";
51      public static final String SEPARATOR = "#";
52  
53      private Class targetClass;
54      
55      private boolean isTransient = false;
56      
57      /** Creates a new instance of EnumConverter */
58      public EnumConverter() {
59      }
60      
61      public EnumConverter(Class targetClass) {
62          if (!targetClass.isEnum()) throw new IllegalArgumentException("targetClass for EnumConverter must be an Enum");
63          this.targetClass = targetClass;
64      }
65  
66      public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value) throws ConverterException {
67          if (facesContext == null) throw new NullPointerException("facesContext can not be null");
68          if (uiComponent == null) throw new NullPointerException("uiComponent can not be null");
69          if (value == null) return "";
70  
71        Class converterClass = null;
72        String idPrefix = "";
73  
74        if (targetClass != null) {
75          converterClass = targetClass;
76        } else if (value.getClass().isEnum()) {
77          converterClass = value.getClass();
78          idPrefix = value.getClass().getName() + SEPARATOR;
79        } else if (value.getClass().getDeclaringClass() != null && value.getClass().getDeclaringClass().isEnum()) {
80          converterClass = value.getClass().getDeclaringClass();
81          idPrefix = value.getClass().getDeclaringClass().getName() + SEPARATOR;
82        }
83  
84        if (converterClass == null || targetClass != null) {
85          checkTargetClass(facesContext, uiComponent, value, converterClass);
86        }
87  
88        for (Object enumConstant : converterClass.getEnumConstants()) {
89          if (enumConstant == value) {
90            return idPrefix + ((Enum)enumConstant).name();
91          }
92        }
93  
94          return value.toString();
95      }
96  
97      public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value) throws ConverterException {
98          if (facesContext == null) throw new NullPointerException("facesContext");
99          if (uiComponent == null) throw new NullPointerException("uiComponent");
100         if (value == null)  return null;
101         value = value.trim();
102         if (value.length() == 0)  return null;
103 
104       Class converterClass = null;
105       String enumName = null;
106 
107       if (targetClass != null) {
108         enumName = value;
109         converterClass = targetClass;
110       } else if (value.indexOf(SEPARATOR) > 0) {
111         int index = value.indexOf(SEPARATOR);
112         if (index < value.length() - 2) {
113           String className = value.substring(0, index);
114           enumName = value.substring(index +1);
115           try {
116             converterClass = Class.forName(className);
117           } catch (ClassNotFoundException e) {
118   //          LOG.error("Catched: " + e.getMessage(), e);
119           }
120         }
121         if (enumName == null || enumName.length() == 0) {
122           return null;
123         }
124       }
125 
126       if (converterClass == null) {
127         checkTargetClass(facesContext, uiComponent, value, converterClass);
128       }
129 
130         // we know targetClass and value can't be null, so we can use Enum.valueOf
131         // instead of the hokey looping called for in the javadoc
132         try {
133           //noinspection unchecked
134           return Enum.valueOf(converterClass, enumName);
135         } catch (IllegalArgumentException e) {
136             Object[] params = new Object[]{value, 
137                                            firstConstantOfEnum(), 
138                                            MessageUtils.getLabel(facesContext, uiComponent)};
139             
140             throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR,
141                                                                        ENUM_ID,
142                                                                        params));
143         }
144     }
145 
146     private void checkTargetClass(FacesContext facesContext, UIComponent uiComponent, Object value, Class converterClass) {
147         if (converterClass == null) {
148             Object[] params = new Object[]{value, MessageUtils.getLabel(facesContext, uiComponent)};
149             throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR,
150                                                                        ENUM_NO_CLASS_ID, 
151                                                                        params));
152         }
153         if (!converterClass.isEnum())
154         {
155             Object[] params = new Object[]{value, MessageUtils.getLabel(facesContext, uiComponent)};
156             throw new ConverterException(MessageUtils.getMessage(FacesMessage.SEVERITY_ERROR,
157                                                                        ENUM_NO_ENUM_CLASS, 
158                                                                        params));
159         }
160     }
161 
162     // find the first constant value of the targetClass and return as a String
163     private String firstConstantOfEnum() {
164         Object[] enumConstants= targetClass.getEnumConstants();
165 
166         if (enumConstants.length != 0 ) return enumConstants[0].toString();
167         
168         return ""; // if empty Enum
169     }
170 
171     public void restoreState(FacesContext context, Object state) {
172         if (state != null)
173         {
174             targetClass = (Class)state;
175         }
176     }
177 
178     public Object saveState(FacesContext context) {
179         if (!initialStateMarked())
180         {
181             return targetClass;
182         }
183         return null;
184     }
185 
186     public void setTransient(boolean newTransientValue) {
187         isTransient = newTransientValue;
188     }
189 
190     public boolean isTransient() {
191         return isTransient;
192     }
193 
194     /**
195      * The enum class to be used for this converter as reference
196      * 
197      */
198     @JSFProperty
199     public Class getTargetClass()
200     {
201         return targetClass;
202     }
203 
204     public void setTargetClass(Class targetClass)
205     {
206         this.targetClass = targetClass;
207         clearInitialState();
208     }
209     
210     private boolean _initialStateMarked = false;
211 
212     public void clearInitialState()
213     {
214         _initialStateMarked = false;
215     }
216 
217     public boolean initialStateMarked()
218     {
219         return _initialStateMarked;
220     }
221 
222     public void markInitialState()
223     {
224         _initialStateMarked = true;
225     }
226 }