View Javadoc

1   /*
2    * Copyright (c) 2009 QOS.ch All rights reserved.
3    * 
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   * 
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   * 
14   * THE SOFTWARE IS PROVIDED "AS  IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package ch.qos.cal10n.verifier;
24  
25  import java.util.ArrayList;
26  import java.util.Enumeration;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Locale;
30  import java.util.ResourceBundle;
31  import java.util.Set;
32  
33  import ch.qos.cal10n.util.AnnotationExtractor;
34  import ch.qos.cal10n.verifier.Cal10nError.ErrorType;
35  
36  /**
37   * Given an enum class, verify that the resource bundles corresponding to a
38   * given locale contains the correct keys.
39   * 
40   * @author Ceki Gulcu
41   */
42  public class MessageKeyVerifier implements IMessageKeyVerifier {
43  
44    Class<? extends Enum<?>> enumType;
45    String enumTypeAsStr;
46  
47    public MessageKeyVerifier(Class<? extends Enum<?>> enumClass) {
48      this.enumType = enumClass;
49      this.enumTypeAsStr = enumClass.getName();
50    }
51  
52    @SuppressWarnings("unchecked")
53    public MessageKeyVerifier(String enumTypeAsStr) {
54      this.enumTypeAsStr = enumTypeAsStr;
55      String errMsg = "Failed to find enum class [" + enumTypeAsStr + "]";
56      try {
57        this.enumType = (Class<? extends Enum<?>>) Class.forName(enumTypeAsStr);
58      } catch (ClassNotFoundException e) {
59        throw new IllegalStateException(errMsg, e);
60      } catch (NoClassDefFoundError e) {
61        throw new IllegalStateException(errMsg, e);
62      }
63    }
64  
65    public Class<? extends Enum<?>> getEnumType() {
66      return enumType;
67    }
68  
69    public String getEnumTypeAsStr() {
70      return enumTypeAsStr;
71    }
72  
73    public List<Cal10nError> verify(Locale locale) {
74      List<Cal10nError> errorList = new ArrayList<Cal10nError>();
75  
76      String resouceBundleName = AnnotationExtractor
77          .getResourceBundleName(enumType);
78  
79      if (resouceBundleName == null) {
80        errorList.add(new Cal10nError(ErrorType.MISSING_RBN_ANNOTATION, "",
81            enumType, locale, ""));
82        // no point in continuing
83        return errorList;
84      }
85  
86      ResourceBundle rb = ResourceBundle.getBundle(resouceBundleName, locale);
87  
88      ErrorFactory errorFactory = new ErrorFactory(enumType, locale,
89          resouceBundleName);
90  
91      if (rb == null) {
92        errorList.add(errorFactory.buildError(ErrorType.FAILED_TO_FIND_RB, ""));
93      }
94  
95      Set<String> rbKeySet = buildKeySetFromEnumeration(rb.getKeys());
96      
97      if (rbKeySet.size() == 0) {
98        errorList.add(errorFactory.buildError(ErrorType.EMPTY_RB, ""));
99      }
100 
101     Enum<?>[] enumArray = enumType.getEnumConstants();
102     if (enumArray == null || enumArray.length == 0) {
103       errorList.add(errorFactory.buildError(ErrorType.EMPTY_ENUM, ""));
104     }
105 
106     if (errorList.size() != 0) {
107       return errorList;
108     }
109 
110     for (Enum<?> e : enumArray) {
111       String enumKey = e.toString();
112       if (rbKeySet.contains(enumKey)) {
113         rbKeySet.remove(enumKey);
114       } else {
115         errorList.add(errorFactory.buildError(ErrorType.ABSENT_IN_RB, enumKey));
116       }
117     }
118 
119     for (String rbKey : rbKeySet) {
120       errorList.add(errorFactory.buildError(ErrorType.ABSENT_IN_ENUM, rbKey));
121     }
122     return errorList;
123   }
124 
125   private Set<String> buildKeySetFromEnumeration(Enumeration<String> e) {
126     Set<String> set = new HashSet<String>(); 
127     while(e.hasMoreElements()) {
128       String s = e.nextElement();
129       set.add(s);
130     }
131     return set;
132   }
133   
134   public List<String> typeIsolatedVerify(Locale locale) {
135     List<Cal10nError> errorList = verify(locale);
136     List<String> strList = new ArrayList<String>();
137     for (Cal10nError error : errorList) {
138       strList.add(error.toString());
139     }
140     return strList;
141   }
142 
143   /***
144    * Verify all declared locales in one step.
145    */
146   public List<Cal10nError> verifyAllLocales() {
147     List<Cal10nError> errorList = new ArrayList<Cal10nError>();
148 
149     String[] localeNameArray = getLocaleNames();
150 
151     if (localeNameArray == null || localeNameArray.length == 0) {
152       String errMsg = "Missing @LocaleNames annotation in enum type ["
153           + enumTypeAsStr + "]";
154       throw new IllegalStateException(errMsg);
155     }
156     for (String localeName : localeNameArray) {
157       Locale locale = new Locale(localeName);
158       List<Cal10nError> tmpList = verify(locale);
159       errorList.addAll(tmpList);
160     }
161 
162     return errorList;
163   }
164 
165   public String[] getLocaleNames() {
166     String[] localeNameArray = AnnotationExtractor.getLocaleNames(enumType);
167     return localeNameArray;
168   }
169 
170   public String getResourceBundleName() {
171     String rbName = AnnotationExtractor.getResourceBundleName(enumType);
172     return rbName;
173   }
174 
175 }