1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 package jnlp.sample.servlet;
38
39 import jnlp.sample.jardiff.JarDiff;
40 import jnlp.sample.util.VersionString;
41
42 import javax.servlet.ServletContext;
43 import java.io.BufferedInputStream;
44 import java.io.BufferedOutputStream;
45 import java.io.File;
46 import java.io.FileOutputStream;
47 import java.io.IOException;
48 import java.io.OutputStream;
49 import java.net.URL;
50 import java.util.HashMap;
51 import java.util.StringTokenizer;
52
53
54
55
56
57 public class JarDiffHandler
58 {
59
60 private static final int BUF_SIZE = 32 * 1024;
61
62
63 private static final String JARDIFF_MIMETYPE = "application/x-java-archive-diff";
64
65
66
67
68 private HashMap _jarDiffEntries = null;
69
70
71
72
73 private static Logger _log = null;
74
75 private ServletContext _servletContext = null;
76
77 private String _jarDiffMimeType = null;
78
79
80 private static class JarDiffKey
81 implements Comparable
82 {
83 private String _name;
84
85 private String _fromVersionId;
86
87 private String _toVersionId;
88
89 private boolean _minimal;
90
91
92
93
94 public JarDiffKey( String name, String fromVersionId, String toVersionId, boolean minimal )
95 {
96 _name = name;
97 _fromVersionId = fromVersionId;
98 _toVersionId = toVersionId;
99 _minimal = minimal;
100 }
101
102
103 public String getName()
104 {
105 return _name;
106 }
107
108 public String getFromVersionId()
109 {
110 return _fromVersionId;
111 }
112
113 public String getToVersionId()
114 {
115 return _toVersionId;
116 }
117
118 public boolean isMinimal()
119 {
120 return _minimal;
121 }
122
123
124
125 public int compareTo( Object o )
126 {
127
128 if ( !( o instanceof JarDiffKey ) )
129 {
130 return -1;
131 }
132 JarDiffKey other = (JarDiffKey) o;
133
134 int n = _name.compareTo( other.getName() );
135 if ( n != 0 )
136 {
137 return n;
138 }
139
140 n = _fromVersionId.compareTo( other.getFromVersionId() );
141 if ( n != 0 )
142 {
143 return n;
144 }
145
146 if ( _minimal != other.isMinimal() )
147 {
148 return -1;
149 }
150
151 return _toVersionId.compareTo( other.getToVersionId() );
152 }
153
154 public boolean equals( Object o )
155 {
156 return compareTo( o ) == 0;
157 }
158
159 public int hashCode()
160 {
161 return _name.hashCode() + _fromVersionId.hashCode() + _toVersionId.hashCode();
162 }
163 }
164
165 static private class JarDiffEntry
166 {
167 private File _jardiffFile;
168
169 public JarDiffEntry( File jarDiffFile )
170 {
171 _jardiffFile = jarDiffFile;
172 }
173
174 public File getJarDiffFile()
175 {
176 return _jardiffFile;
177 }
178 }
179
180
181
182
183 public JarDiffHandler( ServletContext servletContext, Logger log )
184 {
185 _jarDiffEntries = new HashMap();
186 _servletContext = servletContext;
187 _log = log;
188
189 _jarDiffMimeType = _servletContext.getMimeType( "xyz.jardiff" );
190 if ( _jarDiffMimeType == null )
191 {
192 _jarDiffMimeType = JARDIFF_MIMETYPE;
193 }
194 }
195
196
197
198
199 public synchronized DownloadResponse getJarDiffEntry( ResourceCatalog catalog, DownloadRequest dreq,
200 JnlpResource res )
201 {
202 if ( dreq.getCurrentVersionId() == null )
203 {
204 return null;
205 }
206
207
208
209 boolean doJarDiffWorkAround = isJavawsVersion( dreq, "1.0*" );
210
211
212 JarDiffKey key =
213 new JarDiffKey( res.getName(), dreq.getCurrentVersionId(), res.getReturnVersionId(), !doJarDiffWorkAround );
214
215 JarDiffEntry entry = (JarDiffEntry) _jarDiffEntries.get( key );
216
217 if ( entry == null )
218 {
219 if ( _log.isInformationalLevel() )
220 {
221 _log.addInformational( "servlet.log.info.jardiff.gen", res.getName(), dreq.getCurrentVersionId(),
222 res.getReturnVersionId() );
223 }
224 File f = generateJarDiff( catalog, dreq, res, doJarDiffWorkAround );
225 if ( f == null )
226 {
227 _log.addWarning( "servlet.log.warning.jardiff.failed", res.getName(), dreq.getCurrentVersionId(),
228 res.getReturnVersionId() );
229 }
230
231 entry = new JarDiffEntry( f );
232 _jarDiffEntries.put( key, entry );
233 }
234
235
236 if ( entry.getJarDiffFile() == null )
237 {
238 return null;
239 }
240 else
241 {
242 return DownloadResponse.getFileDownloadResponse( entry.getJarDiffFile(), _jarDiffMimeType,
243 entry.getJarDiffFile().lastModified(),
244 res.getReturnVersionId() );
245 }
246 }
247
248
249 public static boolean isJavawsVersion( DownloadRequest dreq, String version )
250 {
251 String javawsAgent = "javaws";
252 String jwsVer = dreq.getHttpRequest().getHeader( "User-Agent" );
253
254
255 if ( !jwsVer.startsWith( "javaws-" ) )
256 {
257
258
259 StringTokenizer st = new StringTokenizer( jwsVer );
260 while ( st.hasMoreTokens() )
261 {
262 String verString = st.nextToken();
263 int index = verString.indexOf( javawsAgent );
264 if ( index != -1 )
265 {
266 verString = verString.substring( index + javawsAgent.length() + 1 );
267 return VersionString.contains( version, verString );
268 }
269 }
270 return false;
271 }
272
273
274 int startIndex = jwsVer.indexOf( "-" );
275
276 if ( startIndex == -1 )
277 {
278 return false;
279 }
280
281 int endIndex = jwsVer.indexOf( "/" );
282
283 if ( endIndex == -1 || endIndex < startIndex )
284 {
285 return false;
286 }
287
288 String verId = jwsVer.substring( startIndex + 1, endIndex );
289
290
291 return VersionString.contains( version, verId );
292
293 }
294
295
296
297
298 private boolean download( URL target, File file )
299 {
300
301 _log.addDebug( "JarDiffHandler: Doing download" );
302
303 boolean ret = true;
304 boolean delete = false;
305
306 BufferedInputStream in = null;
307 BufferedOutputStream out = null;
308 try
309 {
310 in = new BufferedInputStream( target.openStream() );
311 out = new BufferedOutputStream( new FileOutputStream( file ) );
312 int read = 0;
313 int totalRead = 0;
314 byte[] buf = new byte[BUF_SIZE];
315 while ( ( read = in.read( buf ) ) != -1 )
316 {
317 out.write( buf, 0, read );
318 totalRead += read;
319 }
320
321 _log.addDebug( "total read: " + totalRead );
322 _log.addDebug( "Wrote URL " + target.toString() + " to file " + file );
323
324 }
325 catch ( IOException ioe )
326 {
327
328 _log.addDebug( "Got exception while downloading resource: " + ioe );
329
330 ret = false;
331
332 if ( file != null )
333 {
334 delete = true;
335 }
336
337 }
338 finally
339 {
340
341 try
342 {
343 in.close();
344 in = null;
345 }
346 catch ( IOException ioe )
347 {
348 _log.addDebug( "Got exception while downloading resource: " + ioe );
349 }
350
351 try
352 {
353 out.close();
354 out = null;
355 }
356 catch ( IOException ioe )
357 {
358 _log.addDebug( "Got exception while downloading resource: " + ioe );
359 }
360
361 if ( delete )
362 {
363 file.delete();
364 }
365
366 }
367 return ret;
368 }
369
370
371
372
373 private String getRealPath( String path )
374 throws IOException
375 {
376
377 URL fileURL = _servletContext.getResource( path );
378
379 File tempDir = (File) _servletContext.getAttribute( "javax.servlet.context.tempdir" );
380
381
382 if ( fileURL != null )
383 {
384 File newFile = File.createTempFile( "temp", ".jar", tempDir );
385 if ( download( fileURL, newFile ) )
386 {
387 String filePath = newFile.getPath();
388 return filePath;
389 }
390 }
391 return null;
392 }
393
394
395 private File generateJarDiff( ResourceCatalog catalog, DownloadRequest dreq, JnlpResource res,
396 boolean doJarDiffWorkAround )
397 {
398 boolean del_old = false;
399 boolean del_new = false;
400
401
402 DownloadRequest fromDreq = dreq.getFromDownloadRequest();
403 try
404 {
405 JnlpResource fromRes = catalog.lookupResource( fromDreq );
406
407
408 String newFilePath = _servletContext.getRealPath( res.getPath() );
409 String oldFilePath = _servletContext.getRealPath( fromRes.getPath() );
410
411
412 if ( newFilePath == null )
413 {
414 newFilePath = getRealPath( res.getPath() );
415 if ( newFilePath != null )
416 {
417 del_new = true;
418 }
419 }
420
421 if ( oldFilePath == null )
422 {
423 oldFilePath = getRealPath( fromRes.getPath() );
424 if ( oldFilePath != null )
425 {
426 del_old = true;
427 }
428 }
429
430 if ( newFilePath == null || oldFilePath == null )
431 {
432 return null;
433 }
434
435
436 File tempDir = (File) _servletContext.getAttribute( "javax.servlet.context.tempdir" );
437
438
439 File outputFile = File.createTempFile( "jnlp", ".jardiff", tempDir );
440
441 _log.addDebug(
442 "Generating Jardiff between " + oldFilePath + " and " + newFilePath + " Store in " + outputFile );
443
444
445 OutputStream os = new FileOutputStream( outputFile );
446
447 JarDiff.createPatch( oldFilePath, newFilePath, os, !doJarDiffWorkAround );
448 os.close();
449
450 try
451 {
452
453
454 if ( outputFile.length() >= ( new File( newFilePath ).length() ) )
455 {
456 _log.addDebug( "JarDiff discarded - since it is bigger" );
457 return null;
458 }
459
460
461
462 File newFilePacked = new File( newFilePath + ".pack.gz" );
463 if ( newFilePacked.exists() )
464 {
465 _log.addDebug( "generated jardiff size: " + outputFile.length() );
466 _log.addDebug( "packed requesting file size: " + newFilePacked.length() );
467 if ( outputFile.length() >= newFilePacked.length() )
468 {
469 _log.addDebug( "JarDiff discarded - packed version of requesting file is smaller" );
470 return null;
471 }
472 }
473
474 _log.addDebug( "JarDiff generation succeeded" );
475 return outputFile;
476
477 }
478 finally
479 {
480
481 if ( del_new )
482 {
483 new File( newFilePath ).delete();
484 }
485
486 if ( del_old )
487 {
488 new File( oldFilePath ).delete();
489 }
490 }
491 }
492 catch ( IOException ioe )
493 {
494 _log.addDebug( "Failed to genereate jardiff", ioe );
495 return null;
496 }
497 catch ( ErrorResponseException ere )
498 {
499 _log.addDebug( "Failed to genereate jardiff", ere );
500 return null;
501 }
502 }
503 }
504