Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java


1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2003  Oliver Burn
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  package com.puppycrawl.tools.checkstyle.checks;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.util.Enumeration;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Iterator;
30  import java.util.Map;
31  import java.util.Properties;
32  import java.util.Set;
33  
34  import com.puppycrawl.tools.checkstyle.Defn;
35  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
36  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
37  import com.puppycrawl.tools.checkstyle.api.MessageDispatcher;
38  import com.puppycrawl.tools.checkstyle.api.Utils;
39  
40  /**
41   * <p>
42   * The TranslationCheck class helps to ensure the correct translation of code by
43   * checking property files for consistency regarding their keys.
44   * Two property files describing one and the same context are consistent if they
45   * contain the same keys.
46   * </p>
47   * <p>
48   * An example of how to configure the check is:
49   * </p>
50   * <pre>
51   * &lt;module name="Translation"/&gt;
52   * </pre>
53   * @author Alexandra Bunge
54   * @author lkuehne
55   */
56  public class TranslationCheck
57      extends AbstractFileSetCheck
58  {
59      /**
60       * Creates a new <code>TranslationCheck</code> instance.
61       */
62      public TranslationCheck()
63      {
64          setFileExtensions(new String[]{"properties"});
65      }
66  
67      /**
68       * Gets the basename (the unique prefix) of a property file. For example
69       * "xyz/messages" is the basename of "xyz/messages.properties",
70       * "xyz/messages_de_AT.properties", "xyz/messages_en.properties", etc.
71       *
72       * @param aFile the file
73       * @return the extracted basename
74       */
75      private static String extractPropertyIdentifier(final File aFile)
76      {
77          final String filePath = aFile.getPath();
78          final int dirNameEnd = filePath.lastIndexOf(File.separatorChar);
79          final int baseNameStart = dirNameEnd + 1;
80          final int underscoreIdx = filePath.indexOf('_', baseNameStart);
81          final int dotIdx = filePath.indexOf('.', baseNameStart);
82          final int cutoffIdx = (underscoreIdx != -1) ? underscoreIdx : dotIdx;
83          return filePath.substring(0, cutoffIdx);
84      }
85  
86      /**
87       * Arranges a set of property files by their prefix.
88       * The method returns a Map object. The filename prefixes
89       * work as keys each mapped to a set of files.
90       * @param aPropFiles the set of property files
91       * @return a Map object which holds the arranged property file sets
92       */
93      private static Map arrangePropertyFiles(File[] aPropFiles)
94      {
95          final Map propFileMap = new HashMap();
96  
97          for (int i = 0; i < aPropFiles.length; i++) {
98              final File f = aPropFiles[i];
99              final String identifier = extractPropertyIdentifier(f);
100 
101             Set fileSet = (Set) propFileMap.get(identifier);
102             if (fileSet == null) {
103                 fileSet = new HashSet();
104                 propFileMap.put(identifier, fileSet);
105             }
106             fileSet.add(f);
107         }
108         return propFileMap;
109     }
110 
111 
112     /**
113      * Loads the keys of the specified property file into a set.
114      * @param aFile the property file
115      * @return a Set object which holds the loaded keys
116      */
117     private Set loadKeys(File aFile)
118     {
119         final Set keys = new HashSet();
120         InputStream inStream = null;
121 
122         try {
123             // Load file and properties.
124             inStream = new FileInputStream(aFile);
125             Properties props = new Properties();
126             props.load(inStream);
127 
128             // Gather the keys and put them into a set
129             final Enumeration e = props.propertyNames();
130             while (e.hasMoreElements()) {
131                 keys.add(e.nextElement());
132             }
133         }
134         catch (IOException e) {
135             logIOException(e, aFile);
136         }
137         finally {
138             try {
139                 inStream.close();
140             }
141             catch (IOException e) {
142                 logIOException(e, aFile);
143             }
144         }
145         return keys;
146     }
147 
148     /**
149      * helper method to log an io exception.
150      * @param aEx the exception that occured
151      * @param aFile the file that could not be processed
152      */
153     private void logIOException(IOException aEx, File aFile)
154     {
155         String[] args = null;
156         String key = "general.fileNotFound";
157         if (!(aEx instanceof FileNotFoundException)) {
158             args = new String[] {aEx.getMessage()};
159             key = "general.exception";
160         }
161         final LocalizedMessage message =
162             new LocalizedMessage(
163                 0,
164                 Defn.CHECKSTYLE_BUNDLE,
165                 key,
166                 args,
167                 this.getClass());
168         final LocalizedMessage[] messages = new LocalizedMessage[] {message};
169         getMessageDispatcher().fireErrors(aFile.getPath(), messages);
170         Utils.getExceptionLogger().debug("IOException occured.", aEx);
171     }
172 
173 
174     /**
175      * Compares the key sets of the given property files (arranged in a map)
176      * with the specified key set. All missing keys are reported.
177      * @param aKeys the set of keys to compare with
178      * @param aFileMap a Map from property files to their key sets
179      */
180     private void compareKeySets(Set aKeys, Map aFileMap)
181     {
182         final Set fls = aFileMap.keySet();
183 
184         for (Iterator iter = fls.iterator(); iter.hasNext();) {
185             final File currentFile = (File) iter.next();
186             final MessageDispatcher dispatcher = getMessageDispatcher();
187             final String path = currentFile.getPath();
188             dispatcher.fireFileStarted(path);
189             final Set currentKeys = (Set) aFileMap.get(currentFile);
190 
191             // Clone the keys so that they are not lost
192             final Set keysClone = new HashSet(aKeys);
193             keysClone.removeAll(currentKeys);
194 
195             // Remaining elements in the key set are missing in the current file
196             if (!keysClone.isEmpty()) {
197                 for (Iterator it = keysClone.iterator(); it.hasNext();) {
198                     Object key = it.next();
199                     log(0, "translation.missingKey", key);
200                 }
201             }
202             fireErrors(path);
203             dispatcher.fireFileFinished(path);
204         }
205     }
206 
207 
208     /**
209      * Tests whether the given property files (arranged by their prefixes
210      * in a Map) contain the proper keys.
211      *
212      * Each group of files must have the same keys. If this is not the case
213      * an error message is posted giving information which key misses in
214      * which file.
215      *
216      * @param aPropFiles the property files organized as Map
217      */
218     private void checkPropertyFileSets(Map aPropFiles)
219     {
220         final Set keySet = aPropFiles.keySet();
221 
222         for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
223             final String baseName = (String) iterator.next();
224             final Set files = (Set) aPropFiles.get(baseName);
225 
226             if (files.size() >= 2) {
227                 // build a map from files to the keys they contain
228                 final Set keys = new HashSet();
229                 final Map fileMap = new HashMap();
230 
231                 for (Iterator iter = files.iterator(); iter.hasNext();) {
232                     final File file = (File) iter.next();
233                     final Set fileKeys = loadKeys(file);
234                     keys.addAll(fileKeys);
235                     fileMap.put(file, fileKeys);
236                 }
237 
238                 // check the map for consistency
239                 compareKeySets(keys, fileMap);
240             }
241         }
242     }
243 
244 
245     /**
246      * This method searches for property files in the specified file array
247      * and checks whether the key usage is consistent.
248      *
249      * Two property files which have the same prefix should use the same
250      * keys. If this is not the case the missing keys are reported.
251      *
252      * @see com.puppycrawl.tools.checkstyle.api.FileSetCheck
253      */
254     public void process(File[] aFiles)
255     {
256         final File[] propertyFiles = filter(aFiles);
257         final Map propFilesMap = arrangePropertyFiles(propertyFiles);
258         checkPropertyFileSets(propFilesMap);
259     }
260 
261 
262 
263 }