KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inversoft > savant > LocalCacheStore


1 /*
2  * Copyright (c) 2002-2004, Inversoft, All Rights Reserved
3  *
4  * This software is distribuable under the GNU Lesser General Public License.
5  * For more information visit gnu.org.
6  */

7 package com.inversoft.savant;
8
9
10 import java.io.BufferedInputStream JavaDoc;
11 import java.io.BufferedOutputStream JavaDoc;
12 import java.io.File JavaDoc;
13 import java.io.FileInputStream JavaDoc;
14 import java.io.FileNotFoundException JavaDoc;
15 import java.io.FileOutputStream JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.InputStream JavaDoc;
18 import java.security.DigestInputStream JavaDoc;
19 import java.security.MessageDigest JavaDoc;
20 import java.security.NoSuchAlgorithmException JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Date JavaDoc;
23
24 import com.inversoft.savant.log.Log;
25
26
27 /**
28  * <p>
29  * This class is the main store and retrieval unit for items
30  * that are cached locally. Once an artifact is retrieved, it
31  * must be copied to the local cache using this class.
32  * </p>
33  *
34  * <p>
35  * The actual location of the local cache is resolved like
36  * this:
37  * </p>
38  *
39  * <ul>
40  * <li>The File passed into the constructor</li>
41  * <li>If constructor parameter is null, System property
42  * named <b>savant.local.repository</b></li>
43  * <li>If no system property, a directory in the users home
44  * directory named <b>.savant_repository</b></li>
45  * </ul>
46  *
47  * @author Brian Pontarelli
48  */

49 public class LocalCacheStore {
50
51     private File JavaDoc localCache;
52
53
54     /**
55      * Constructs a new <code>LocalCacheStore</code>.
56      *
57      * @param localCache The location of the local cache
58      * @throws SavantException If the file location is not null and not a
59      * directory
60      */

61     public LocalCacheStore(File JavaDoc localCache) throws SavantException {
62         if (localCache == null) {
63             String JavaDoc localCacheDir = System.getProperty("savant.local.repository");
64             if (localCacheDir == null) {
65                 localCacheDir = System.getProperty("user.home") + File.separator +
66                     ".savant_repository";
67             }
68
69             localCache = new File JavaDoc(localCacheDir);
70         }
71
72         this.localCache = localCache;
73         if (!localCache.exists()) {
74             localCache.mkdir();
75         } else if (localCache.isFile() || !localCache.canWrite() ||
76                 !localCache.canRead()) {
77             throw new SavantException("Local cache directory [" +
78                 localCache.getAbsolutePath() + " is invalid");
79         }
80     }
81
82     /**
83      * Returns the local cache location.
84      *
85      * @return The location
86      */

87     public File JavaDoc getLocation() {
88         return localCache;
89     }
90
91     /**
92      * Resolves the artifact dependencies from the local cache (if they exist)
93      * by looking up the dependency XML file and parsing it out. If the file
94      * exists and can be read, the given artifact is updated with its dependencies.
95      *
96      * @param artifact The artifact to update.
97      * @return True if the artifact was updated, false otherwise.
98      * @throws SavantException If the parsing of the dependencies file failed
99      * for any reason.
100      */

101     public boolean resolveArtifactDependencies(Artifact artifact)
102         throws SavantException {
103         String JavaDoc artDepsFile = artifact.getArtifactDepsFile();
104         File JavaDoc file = new File JavaDoc(localCache, artDepsFile);
105         if (!file.exists() || !file.isFile()) {
106             return false;
107         }
108
109         ArtifactTools.resolveArtifactDependencies(artifact, file);
110         return true;
111     }
112
113     /**
114      * Finds the locally cached copy of the artifact, if it exists and all the
115      * dependencies that the artifact depends on.
116      *
117      * @param artifact The artifact to locate
118      * @return The artifact file and its dependency files or null if it does
119      * not exist
120      */

121     public File JavaDoc find(Artifact artifact) {
122         String JavaDoc artifactFile = artifact.getArtifactFile();
123         File JavaDoc file = new File JavaDoc(localCache, artifactFile);
124         if (!file.exists() || !file.isFile()) {
125             file = null;
126         } else {
127
128             // Check for expiration using minutes and fixed time
129
long curTimeMins = System.currentTimeMillis() / 60000;
130             int expiry = artifact.getExpireminutes();
131             if (expiry > 0) {
132                 long time = file.lastModified() / 60000;
133                 if ((time + expiry) < curTimeMins) {
134                     file = null;
135                 }
136             }
137
138             long curTime = System.currentTimeMillis();
139             Date JavaDoc expiryDate = artifact.getExpiretime();
140             if (expiryDate != null && curTime > expiryDate.getTime()) {
141                 file = null;
142             }
143         }
144
145         return file;
146     }
147
148     /**
149      * Makes a local copy to the local cache location of the file specified. The
150      * name of the file remains the same.
151      *
152      * @param artifact The artifact descriptor that describes the file parameter
153      * in terms of an artifact.
154      * @param file The file to copy
155      * @return The file stored in the local cache and never null
156      */

157     public File JavaDoc store(Artifact artifact, File JavaDoc file) throws SavantException {
158         try {
159             FileInputStream JavaDoc stream = new FileInputStream JavaDoc(file);
160             File JavaDoc cached = store(artifact, stream, null, true);
161             stream.close();
162             return cached;
163         } catch (FileNotFoundException JavaDoc fnfe) {
164             throw new SavantException(fnfe);
165         } catch (IOException JavaDoc ioe) {
166             throw new SavantException(ioe);
167         }
168     }
169
170     /**
171      * <p>
172      * Makes a local copy to the local cache location of the bytes that will be
173      * read from the input stream given. This local copy will have a create and
174      * modified date of the current system time when it is stored.
175      * </p>
176      *
177      * <p><b>NOTE</b> The caller must close the input stream given</p>
178      *
179      * @param artifact The artifact descriptor that describes the file parameter
180      * in terms of an artifact.
181      * @param stream The InputStream to read from.
182      * @param remoteMD5 (Optional) The MD5 hash of the input file read from an
183      * external source that can be compared to the bytes read from the
184      * input file.
185      * @param failonmd5 Determines whether or not this should fail or simply
186      * warn on MD5 errors. Many MD5 hashes are bad and this can prevent
187      * failures.
188      * @return The file stored in the local cache and never null
189      */

190     public File JavaDoc store(Artifact artifact, InputStream JavaDoc stream, byte[] remoteMD5,
191             boolean failonmd5)
192     throws SavantException {
193         String JavaDoc artifactFile = artifact.getArtifactFile();
194         File JavaDoc file = new File JavaDoc(localCache, artifactFile);
195         construct(file);
196
197         try {
198             // Copy to the file can do the MD5 sum while copying
199
MessageDigest JavaDoc digest = null;
200             try {
201                 digest = MessageDigest.getInstance("MD5");
202                 digest.reset();
203             } catch (NoSuchAlgorithmException JavaDoc e) {
204                 System.err.println("Unable to locate MD5 algorithm");
205                 System.exit(1);
206             }
207
208             FileOutputStream JavaDoc os = new FileOutputStream JavaDoc(file);
209             BufferedOutputStream JavaDoc bos = new BufferedOutputStream JavaDoc(os);
210             BufferedInputStream JavaDoc bis = new BufferedInputStream JavaDoc(stream);
211             DigestInputStream JavaDoc dis = new DigestInputStream JavaDoc(bis, digest);
212             dis.on(true);
213
214             byte[] ba = new byte[1024];
215             int count;
216             while ((count = dis.read(ba, 0, 1024)) != -1) {
217                 bos.write(ba, 0, count);
218             }
219
220             dis.close();
221             bos.close();
222             bis.close();
223             os.close();
224
225             byte[] localMD5 = digest.digest();
226             if (remoteMD5 != null && localMD5 != null &&
227                     !Arrays.equals(localMD5, remoteMD5)) {
228
229                 if (failonmd5) {
230                     file.delete();
231                     throw new SavantException("Downloaded artifact [" + artifact +
232                         "] corrupt according to MD5. Attempt rebuilding when remote" +
233                         " repository is fixed");
234                 } else {
235                     Log.log("Downloaded artifact [" + artifact + "] corrupt" +
236                         " according to MD5.", Log.WARN);
237                 }
238             }
239         } catch (FileNotFoundException JavaDoc fnfe) {
240             throw new SavantException(fnfe);
241         } catch (IOException JavaDoc ioe) {
242             throw new SavantException(ioe);
243         }
244
245         return file;
246     }
247
248     /**
249      * Makes a local copy to the local cache location of the file specified. The
250      * name of the file remains the same.
251      *
252      * @param artifact The artifact descriptor that describes the file parameter
253      * in terms of an artifact.
254      * @param file The file to copy
255      */

256     public void storeDeps(Artifact artifact, File JavaDoc file) throws SavantException {
257         try {
258             File JavaDoc cached = new File JavaDoc(localCache, artifact.getArtifactDepsFile());
259             FileInputStream JavaDoc fis = new FileInputStream JavaDoc(file);
260             FileTools.output(fis, cached);
261         } catch (IOException JavaDoc ioe) {
262             throw new SavantException(ioe);
263         }
264     }
265
266     /**
267      * Deletes the artifact (if it exists) from the local cache.
268      *
269      * @param artifact The artifact descriptor that describes the file parameter
270      * in terms of an artifact.
271      * @return True if the artifact was deleted, false otherwise
272      */

273     public boolean delete(Artifact artifact) {
274         File JavaDoc file = new File JavaDoc(localCache, artifact.getArtifactFile());
275         boolean deleted = false;
276         if (file.exists()) {
277             deleted = file.delete();
278         }
279
280         return deleted;
281     }
282
283     /**
284      * Mis-leading, but this method verifies that the file is up-to-date and if
285      * it isn't, it clears out the file so that it can be stored from the remote
286      * source.
287      */

288     private void construct(File JavaDoc file) throws SavantException {
289
290         if (file.exists() && file.isDirectory()) {
291             throw new SavantException("ArtifactType location is a directory [" +
292                 file.getAbsolutePath() +"]");
293         }
294
295         if (file.exists() && file.isFile()) {
296             file.delete();
297         } else if (!file.exists()) {
298             File JavaDoc dir = file.getParentFile();
299             dir.mkdirs();
300         }
301
302         try {
303             file.createNewFile();
304         } catch (IOException JavaDoc ioe) {
305             throw new SavantException(ioe);
306         }
307     }
308 }
Free Books   Free Magazines  
Popular Tags