KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jnlp > sample > servlet > JarDiffHandler


1 /*
2  * @(#)JarDiffHandler.java 1.9 05/11/30
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 package jnlp.sample.servlet;
38 import java.io.*;
39 import java.util.*;
40 import jnlp.sample.jardiff.*;
41 import javax.servlet.*;
42 import javax.servlet.http.*;
43 import jnlp.sample.util.VersionString;
44 import java.net.URL JavaDoc;
45 /*
46  * A class that generates and caches information about JarDiff files
47  *
48  */

49 public class JarDiffHandler {
50     // Default size of download buffer
51
private static final int BUF_SIZE = 32 * 1024;
52     
53     // Default JARDiff mime type
54
private static final String JavaDoc JARDIFF_MIMETYPE = "application/x-java-archive-diff";
55     
56     /** List of all generated JARDiffs */
57     private HashMap _jarDiffEntries = null;
58     
59     /** Reference to ServletContext and logger object */
60     private static Logger _log = null;
61     private ServletContext _servletContext = null;
62     private String JavaDoc _jarDiffMimeType = null;
63     
64     /* Contains information about a particular JARDiff entry */
65     private static class JarDiffKey implements Comparable JavaDoc{
66     private String JavaDoc _name; // Name of file
67
private String JavaDoc _fromVersionId; // From version
68
private String JavaDoc _toVersionId; // To version
69
private boolean _minimal; // True if this is a minimal jardiff
70

71     /** Constructor used to generate a query object */
72     public JarDiffKey(String JavaDoc name, String JavaDoc fromVersionId, String JavaDoc toVersionId, boolean minimal) {
73         _name = name;
74         _fromVersionId = fromVersionId;
75         _toVersionId = toVersionId;
76         _minimal = minimal;
77     }
78     
79     // Query methods
80
public String JavaDoc getName() { return _name; }
81     public String JavaDoc getFromVersionId() { return _fromVersionId; }
82     public String JavaDoc getToVersionId() { return _toVersionId; }
83     public boolean isMinimal() { return _minimal; }
84     
85     // Collection framework interface methods
86

87     public int compareTo(Object JavaDoc o) {
88         // All non JarDiff entries are less
89
if (!(o instanceof JarDiffKey)) return -1;
90         JarDiffKey other = (JarDiffKey)o;
91         
92         int n = _name.compareTo(other.getName());
93         if (n != 0) return n;
94         
95         n = _fromVersionId.compareTo(other.getFromVersionId());
96         if (n != 0) return n;
97
98         if (_minimal != other.isMinimal()) return -1;
99         
100         return _toVersionId.compareTo(other.getToVersionId());
101     }
102     
103     public boolean equals(Object JavaDoc o) {
104         return compareTo(o) == 0;
105     }
106     
107     public int hashCode() {
108         return _name.hashCode() +
109         _fromVersionId.hashCode() +
110         _toVersionId.hashCode();
111     }
112     }
113     
114     static private class JarDiffEntry {
115     private File _jardiffFile; // Location of JARDiff file
116

117     public JarDiffEntry(File jarDiffFile) {
118         _jardiffFile = jarDiffFile;
119     }
120     
121     public File getJarDiffFile() { return _jardiffFile; }
122     }
123     
124     /** Initialize JarDiff handler */
125     public JarDiffHandler(ServletContext servletContext, Logger log) {
126     _jarDiffEntries = new HashMap();
127     _servletContext = servletContext;
128     _log = log;
129     
130     _jarDiffMimeType = _servletContext.getMimeType("xyz.jardiff");
131     if (_jarDiffMimeType == null) _jarDiffMimeType = JARDIFF_MIMETYPE;
132     }
133     
134     /** Returns a JarDiff for the given request */
135     public synchronized DownloadResponse getJarDiffEntry(ResourceCatalog catalog, DownloadRequest dreq, JnlpResource res) {
136     if (dreq.getCurrentVersionId() == null) return null;
137     
138     // check whether the request is from javaws 1.0/1.0.1
139
// do not generate minimal jardiff if it is from 1.0/1.0.1
140
boolean doJarDiffWorkAround = isJavawsVersion(dreq, "1.0*");
141
142     // First do a lookup to find a match
143
JarDiffKey key = new JarDiffKey(res.getName(),
144                     dreq.getCurrentVersionId(),
145                     res.getReturnVersionId(),
146                     !doJarDiffWorkAround);
147     
148
149     JarDiffEntry entry = (JarDiffEntry)_jarDiffEntries.get(key);
150     // If entry is not found, then the querty has not been made.
151
if (entry == null) {
152         if (_log.isInformationalLevel()) {
153         _log.addInformational("servlet.log.info.jardiff.gen",
154                       res.getName(),
155                       dreq.getCurrentVersionId(),
156                       res.getReturnVersionId());
157         }
158         File f = generateJarDiff(catalog, dreq, res, doJarDiffWorkAround);
159         if (f == null) {
160         _log.addWarning("servlet.log.warning.jardiff.failed",
161                 res.getName(),
162                 dreq.getCurrentVersionId(),
163                 res.getReturnVersionId());
164         }
165         // Store entry in table
166
entry = new JarDiffEntry(f);
167         _jarDiffEntries.put(key, entry);
168     }
169     
170     
171     
172     // Check for no JarDiff to return
173
if (entry.getJarDiffFile() == null) {
174         return null;
175     } else {
176         return DownloadResponse.getFileDownloadResponse(entry.getJarDiffFile(),
177                                 _jarDiffMimeType,
178                                 entry.getJarDiffFile().lastModified(),
179                                 res.getReturnVersionId());
180     }
181     }
182     
183
184     public static boolean isJavawsVersion(DownloadRequest dreq, String JavaDoc version) {
185     String JavaDoc javawsAgent = "javaws";
186     String JavaDoc jwsVer = dreq.getHttpRequest().getHeader("User-Agent");
187
188
189     // check the request is coming from javaws
190
if (!jwsVer.startsWith("javaws-")) {
191         // this is the new style User-Agent string
192
// User-Agent: JNLP/1.0.1 javaws/1.4.2 (b28) J2SE/1.4.2
193
StringTokenizer st = new StringTokenizer(jwsVer);
194         while (st.hasMoreTokens()) {
195         String JavaDoc verString = st.nextToken();
196         int index = verString.indexOf(javawsAgent);
197         if (index != -1) {
198             verString = verString.substring(index + javawsAgent.length() + 1);
199             return VersionString.contains(version, verString);
200         }
201         }
202         return false;
203     }
204
205     // extract the version id from the download request
206
int startIndex = jwsVer.indexOf("-");
207
208     if (startIndex == -1) {
209         return false;
210     }
211
212     int endIndex = jwsVer.indexOf("/");
213
214     if (endIndex == -1 || endIndex < startIndex) {
215         return false;
216     }
217
218     String JavaDoc verId = jwsVer.substring(startIndex + 1, endIndex);
219
220
221     // check whether the versionString contains the versionId
222
return VersionString.contains(version, verId);
223
224     }
225
226     /** Download resource to the given file */
227     private boolean download(URL JavaDoc target, File file) {
228
229     _log.addDebug("JarDiffHandler: Doing download");
230
231     boolean ret = true;
232     boolean delete = false;
233     // use bufferedstream for better performance
234
BufferedInputStream in = null;
235     BufferedOutputStream out = null;
236     try {
237         in = new BufferedInputStream(target.openStream());
238         out = new BufferedOutputStream(new FileOutputStream(file));
239         int read = 0;
240         int totalRead = 0;
241         byte[] buf = new byte[BUF_SIZE];
242         while ((read = in.read(buf)) != -1) {
243         out.write(buf, 0, read);
244         totalRead += read;
245         }
246
247         _log.addDebug("total read: " + totalRead);
248         _log.addDebug("Wrote URL " + target.toString() + " to file " + file);
249        
250     } catch(IOException ioe) {
251       
252         _log.addDebug("Got exception while downloading resource: " + ioe);
253         
254         ret = false;
255       
256         if (file != null) delete = true;
257         
258     } finally {
259         
260         try {
261         in.close();
262         in = null;
263         } catch (IOException ioe) {
264         _log.addDebug("Got exception while downloading resource: " + ioe);
265         }
266
267         try {
268         out.close();
269         out = null;
270         } catch (IOException ioe) {
271         _log.addDebug("Got exception while downloading resource: " + ioe);
272         }
273
274         if (delete) {
275         file.delete();
276         }
277
278     }
279     return ret;
280     }
281
282     // fix for 4720897
283
// if the jar file resides in a war file, download it to a temp dir
284
// so it can be used to generate jardiff
285
private String JavaDoc getRealPath(String JavaDoc path) throws IOException{
286
287     URL JavaDoc fileURL = _servletContext.getResource(path);
288     
289     File tempDir = (File)_servletContext.getAttribute("javax.servlet.context.tempdir");
290
291     // download file into temp dir
292
if (fileURL != null) {
293         File newFile = File.createTempFile("temp", ".jar", tempDir);
294         if (download(fileURL, newFile)) {
295         String JavaDoc filePath = newFile.getPath();
296         return filePath;
297         }
298     }
299     return null;
300     }
301
302
303     private File generateJarDiff(ResourceCatalog catalog, DownloadRequest dreq, JnlpResource res, boolean doJarDiffWorkAround) {
304     boolean del_old = false;
305     boolean del_new = false;
306
307     // Lookup up file for request version
308
DownloadRequest fromDreq = dreq.getFromDownloadRequest();
309     try {
310         JnlpResource fromRes = catalog.lookupResource(fromDreq);
311         
312         /* Get file locations */
313         String JavaDoc newFilePath = _servletContext.getRealPath(res.getPath());
314         String JavaDoc oldFilePath = _servletContext.getRealPath(fromRes.getPath());
315                         
316         // fix for 4720897
317
if (newFilePath == null) {
318         newFilePath = getRealPath(res.getPath());
319         if (newFilePath != null) del_new = true;
320         }
321
322         if (oldFilePath == null) {
323         oldFilePath = getRealPath(fromRes.getPath());
324         if (oldFilePath != null) del_old = true;
325         }
326                                
327         if (newFilePath == null || oldFilePath == null) {
328         return null;
329         }
330         
331         // Create temp. file to store JarDiff file in
332
File tempDir = (File)_servletContext.getAttribute("javax.servlet.context.tempdir");
333
334         // fix for 4653036: JarDiffHandler() should use javax.servlet.context.tempdir to store the jardiff
335
File outputFile = File.createTempFile("jnlp", ".jardiff", tempDir);
336           
337         _log.addDebug("Generating Jardiff between " + oldFilePath + " and " +
338                   newFilePath + " Store in " + outputFile);
339         
340         // Generate JarDiff
341
OutputStream os = new FileOutputStream(outputFile);
342
343         JarDiff.createPatch(oldFilePath, newFilePath, os, !doJarDiffWorkAround);
344         os.close();
345         
346         try {
347
348         // Check that Jardiff is smaller, or return null
349
if (outputFile.length() >= (new File(newFilePath).length())) {
350             _log.addDebug("JarDiff discarded - since it is bigger");
351             return null;
352         }
353         
354         // Check that Jardiff is smaller than the packed version of
355
// the new file, if the file exists at all
356
File newFilePacked = new File(newFilePath + ".pack.gz");
357         if (newFilePacked.exists()) {
358             _log.addDebug("generated jardiff size: " + outputFile.length());
359             _log.addDebug("packed requesting file size: " + newFilePacked.length());
360             if (outputFile.length() >= newFilePacked.length()) {
361             _log.addDebug("JarDiff discarded - packed version of requesting file is smaller");
362             return null;
363             }
364         }
365         
366         _log.addDebug("JarDiff generation succeeded");
367         return outputFile;
368
369         } finally {
370         // delete the temporarily downloaded file
371
if (del_new) {
372             new File(newFilePath).delete();
373         }
374         
375         if (del_old) {
376             new File(oldFilePath).delete();
377         }
378         }
379     } catch(IOException ioe) {
380         _log.addDebug("Failed to genereate jardiff", ioe);
381         return null;
382     } catch(ErrorResponseException ere) {
383         _log.addDebug("Failed to genereate jardiff", ere);
384         return null;
385     }
386     }
387 }
388
389
Popular Tags