KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > PropertyCacheFile


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2005 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;
20
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileNotFoundException JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.ByteArrayOutputStream JavaDoc;
26 import java.io.ObjectOutputStream JavaDoc;
27 import java.io.Serializable JavaDoc;
28 import java.util.Properties JavaDoc;
29 import java.security.MessageDigest JavaDoc;
30
31 import com.puppycrawl.tools.checkstyle.api.Configuration;
32 import com.puppycrawl.tools.checkstyle.api.Utils;
33
34 /**
35  * This class maintains a persistent store of the files that have
36  * checked ok and their associated timestamp. It uses a property file
37  * for storage. A hashcode of the Configuration is stored in the
38  * cache file to ensure the cache is invalidated when the
39  * configuration has changed.
40  *
41  * @author Oliver Burn
42  */

43 final class PropertyCacheFile
44 {
45     /**
46      * The property key to use for storing the hashcode of the
47      * configuration. To avoid nameclashes with the files that are
48      * checked the key is chosen in such a way that it cannot be a
49      * valid file name.
50      */

51     private static final String JavaDoc CONFIG_HASH_KEY = "configuration*?";
52
53     /** name of file to store details **/
54     private final String JavaDoc mDetailsFile;
55     /** the details on files **/
56     private final Properties JavaDoc mDetails = new Properties JavaDoc();
57
58     /**
59      * Creates a new <code>PropertyCacheFile</code> instance.
60      *
61      * @param aCurrentConfig the current configuration, not null
62      * @param aFileName the cache file
63      */

64     PropertyCacheFile(Configuration aCurrentConfig, String JavaDoc aFileName)
65     {
66         boolean setInActive = true;
67         if (aFileName != null) {
68             FileInputStream JavaDoc inStream = null;
69             // get the current config so if the file isn't found
70
// the first time the hash will be added to output file
71
final String JavaDoc currentConfigHash = getConfigHashCode(aCurrentConfig);
72             try {
73                 inStream = new FileInputStream JavaDoc(aFileName);
74                 mDetails.load(inStream);
75                 final String JavaDoc cachedConfigHash =
76                     mDetails.getProperty(CONFIG_HASH_KEY);
77                 setInActive = false;
78                 if ((cachedConfigHash == null)
79                     || !cachedConfigHash.equals(currentConfigHash))
80                 {
81                     // Detected configuration change - clear cache
82
mDetails.clear();
83                     mDetails.put(CONFIG_HASH_KEY, currentConfigHash);
84                 }
85             }
86             catch (final FileNotFoundException JavaDoc e) {
87                 // Ignore, the cache does not exist
88
setInActive = false;
89                 // put the hash in the file if the file is going to be created
90
mDetails.put(CONFIG_HASH_KEY, currentConfigHash);
91             }
92             catch (final IOException JavaDoc e) {
93                 Utils.getExceptionLogger()
94                     .debug("Unable to open cache file, ignoring.", e);
95             }
96             finally {
97                 if (inStream != null) {
98                     try {
99                         inStream.close();
100                     }
101                     catch (final IOException JavaDoc ex) {
102                         Utils.getExceptionLogger()
103                             .debug("Unable to close cache file.", ex);
104                     }
105                 }
106             }
107         }
108         mDetailsFile = (setInActive) ? null : aFileName;
109     }
110
111     /** Cleans up the object and updates the cache file. **/
112     void destroy()
113     {
114         if (mDetailsFile != null) {
115             FileOutputStream JavaDoc out = null;
116             try {
117                 out = new FileOutputStream JavaDoc(mDetailsFile);
118                 mDetails.store(out, null);
119             }
120             catch (final IOException JavaDoc e) {
121                 Utils.getExceptionLogger()
122                     .debug("Unable to save cache file.", e);
123             }
124             finally {
125                 if (out != null) {
126                     try {
127                         out.flush();
128                         out.close();
129                     }
130                     catch (final IOException JavaDoc ex) {
131                         Utils.getExceptionLogger()
132                             .debug("Unable to close cache file.", ex);
133                     }
134                 }
135             }
136         }
137     }
138
139     /**
140      * @return whether the specified file has already been checked ok
141      * @param aFileName the file to check
142      * @param aTimestamp the timestamp of the file to check
143      */

144     boolean alreadyChecked(String JavaDoc aFileName, long aTimestamp)
145     {
146         final String JavaDoc lastChecked = mDetails.getProperty(aFileName);
147         return (lastChecked != null)
148             && (lastChecked.equals(Long.toString(aTimestamp)));
149     }
150
151     /**
152      * Records that a file checked ok.
153      * @param aFileName name of the file that checked ok
154      * @param aTimestamp the timestamp of the file
155      */

156     void checkedOk(String JavaDoc aFileName, long aTimestamp)
157     {
158         mDetails.put(aFileName, Long.toString(aTimestamp));
159     }
160
161     /**
162      * Calculates the hashcode for a GlobalProperties.
163      *
164      * @param aConfiguration the GlobalProperties
165      * @return the hashcode for <code>aConfiguration</code>
166      */

167     private String JavaDoc getConfigHashCode(Serializable JavaDoc aConfiguration)
168     {
169         try {
170             // im-memory serialization of Configuration
171

172             final ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
173             final ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(baos);
174             oos.writeObject(aConfiguration);
175             oos.flush();
176             oos.close();
177
178             // Instead of hexEncoding baos.toByteArray() directly we
179
// use a message digest here to keep the length of the
180
// hashcode reasonable
181

182             final MessageDigest JavaDoc md = MessageDigest.getInstance("SHA");
183             md.update(baos.toByteArray());
184
185             return hexEncode(md.digest());
186         }
187         catch (final Exception JavaDoc ex) { // IO, NoSuchAlgorithm
188
Utils.getExceptionLogger()
189                 .debug("Unable to calculate hashcode.", ex);
190             return "ALWAYS FRESH: " + System.currentTimeMillis();
191         }
192     }
193
194     /** hex digits */
195     private static final char[] HEX_CHARS = {
196         '0', '1', '2', '3', '4', '5', '6', '7',
197         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
198     };
199
200     /** mask for last byte */
201     private static final int MASK_0X0F = 0x0F;
202
203     /** bit shift */
204     private static final int SHIFT_4 = 4;
205
206     /**
207      * Hex-encodes a byte array.
208      * @param aByteArray the byte array
209      * @return hex encoding of <code>aByteArray</code>
210      */

211     private static String JavaDoc hexEncode(byte[] aByteArray)
212     {
213         final StringBuffer JavaDoc buf = new StringBuffer JavaDoc(2 * aByteArray.length);
214         for (int i = 0; i < aByteArray.length; i++) {
215             final int b = aByteArray[i];
216             final int low = b & MASK_0X0F;
217             final int high = (b >> SHIFT_4) & MASK_0X0F;
218             buf.append(HEX_CHARS[high]);
219             buf.append(HEX_CHARS[low]);
220         }
221         return buf.toString();
222     }
223 }
224
Popular Tags