KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jnlp > sample > jardiff > JarDiffPatcher


1 /*
2  * @(#)JarDiffPatcher.java 1.7 05/11/17
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.jardiff;
38  
39 import java.io.*;
40 import java.util.*;
41 import java.net.URL JavaDoc;
42 import java.util.jar.*;
43 import java.util.zip.*;
44
45 /**
46  * JarDiff is able to create a jar file containing the delta between two
47  * jar files (old and new). The delta jar file can then be applied to the
48  * old jar file to reconstruct the new jar file.
49  * <p>
50  * Refer to the JNLP spec for details on how this is done.
51  *
52  * @version 1.11, 06/26/03
53  */

54 public class JarDiffPatcher implements JarDiffConstants, Patcher {
55     private static final int DEFAULT_READ_SIZE = 2048;
56     private static byte[] newBytes = new byte[DEFAULT_READ_SIZE];
57     private static byte[] oldBytes = new byte[DEFAULT_READ_SIZE];
58     private static ResourceBundle _resources = JarDiff.getResources();
59
60     public static ResourceBundle getResources() {
61     return JarDiff.getResources();
62     }
63     
64     public void applyPatch(Patcher.PatchDelegate delegate, String JavaDoc oldJarPath,
65                            String JavaDoc jarDiffPath, OutputStream result) throws IOException {
66             File oldFile = new File(oldJarPath);
67             File diffFile = new File(jarDiffPath);
68             JarOutputStream jos = new JarOutputStream(result);
69             JarFile oldJar = new JarFile(oldFile);
70             JarFile jarDiff = new JarFile(diffFile);
71             Set ignoreSet = new HashSet();
72             Map renameMap = new HashMap();
73       
74             
75             determineNameMapping(jarDiff, ignoreSet, renameMap);
76
77         // get all keys in renameMap
78
Object JavaDoc[] keys = renameMap.keySet().toArray();
79        
80        
81         // Files to implicit move
82
Set oldjarNames = new HashSet();
83         
84         Enumeration oldEntries = oldJar.entries();
85         if (oldEntries != null) {
86         while (oldEntries.hasMoreElements()) {
87             oldjarNames.add(((JarEntry)oldEntries.nextElement()).getName());
88         }
89         }
90        
91         // size depends on the three parameters below, which is
92
// basically the counter for each loop that do the actual
93
// writes to the output file
94
// since oldjarNames.size() changes in the first two loop
95
// below, we need to adjust the size accordingly also when
96
// oldjarNames.size() changes
97
double size = oldjarNames.size() + keys.length + jarDiff.size();
98         double currentEntry = 0;
99
100         // Handle all remove commands
101
oldjarNames.removeAll(ignoreSet);
102         size -= ignoreSet.size();
103                
104                  
105         // Add content from JARDiff
106
Enumeration entries = jarDiff.entries();
107         if (entries != null) {
108         while (entries.hasMoreElements()) {
109             JarEntry entry = (JarEntry)entries.nextElement();
110             
111            
112
113             if (!INDEX_NAME.equals(entry.getName())) {
114             
115             updateDelegate(delegate, currentEntry, size);
116             currentEntry++;
117                 
118             writeEntry(jos, entry, jarDiff);
119
120             // Remove entry from oldjarNames since no implicit
121
//move is needed
122
boolean wasInOld = oldjarNames.remove(entry.getName());
123
124             // Update progress counters. If it was in old, we do
125
// not need an implicit move, so adjust total size.
126
if (wasInOld) size--;
127         
128             }
129             else {
130             // no write is done, decrement size
131
size--;
132             }
133         }
134         }
135
136        
137
138         // go through the renameMap and apply move for each entry
139
for (int j = 0; j < keys.length; j++) {
140     
141     
142
143         // Apply move <oldName> <newName> command
144
String JavaDoc newName = (String JavaDoc)keys[j];
145         String JavaDoc oldName = (String JavaDoc)renameMap.get(newName);
146
147         // Get source JarEntry
148
JarEntry oldEntry = oldJar.getJarEntry(oldName);
149             
150         if (oldEntry == null) {
151             String JavaDoc moveCmd = MOVE_COMMAND + oldName + " " + newName;
152             handleException("jardiff.error.badmove", moveCmd);
153         }
154
155         // Create dest JarEntry
156
JarEntry newEntry = new JarEntry(newName);
157         newEntry.setTime(oldEntry.getTime());
158         newEntry.setSize(oldEntry.getSize());
159         newEntry.setCompressedSize(oldEntry.getCompressedSize());
160         newEntry.setCrc(oldEntry.getCrc());
161         newEntry.setMethod(oldEntry.getMethod());
162         newEntry.setExtra(oldEntry.getExtra());
163         newEntry.setComment(oldEntry.getComment());
164
165     
166         updateDelegate(delegate, currentEntry, size);
167         currentEntry++;
168     
169         writeEntry(jos, newEntry, oldJar.getInputStream(oldEntry));
170
171         // Remove entry from oldjarNames since no implicit
172
//move is needed
173
boolean wasInOld = oldjarNames.remove(oldName);
174
175         // Update progress counters. If it was in old, we do
176
// not need an implicit move, so adjust total size.
177
if (wasInOld) size--;
178     
179         }
180
181         // implicit move
182
Iterator iEntries = oldjarNames.iterator();
183             if (iEntries != null) {
184                 while (iEntries.hasNext()) {
185            
186                     String JavaDoc name = (String JavaDoc)iEntries.next();
187             JarEntry entry = oldJar.getJarEntry(name);
188            
189             updateDelegate(delegate, currentEntry, size);
190             currentEntry++;
191                                                   
192             writeEntry(jos, entry, oldJar);
193                 }
194             }
195             
196         updateDelegate(delegate, currentEntry, size);
197           
198             jos.finish();
199     }
200     
201     private void updateDelegate(Patcher.PatchDelegate delegate, double currentSize, double size) {
202     if (delegate != null) {
203         delegate.patching((int)(currentSize/size));
204     }
205     }
206
207     private void determineNameMapping(JarFile jarDiff, Set ignoreSet,
208                                       Map renameMap) throws IOException {
209         InputStream is = jarDiff.getInputStream(jarDiff.getEntry(INDEX_NAME));
210         
211         if (is == null) {
212         handleException("jardiff.error.noindex", null);
213        
214     }
215         LineNumberReader indexReader = new LineNumberReader
216             (new InputStreamReader(is, "UTF-8"));
217         String JavaDoc line = indexReader.readLine();
218         
219         if (line == null || !line.equals(VERSION_HEADER)) {
220         handleException("jardiff.error.badheader", line);
221         
222         }
223         
224         while ((line = indexReader.readLine()) != null) {
225             if (line.startsWith(REMOVE_COMMAND)) {
226                 List sub = getSubpaths(line.substring(REMOVE_COMMAND.
227                                                           length()));
228                 
229                 if (sub.size() != 1) {
230             handleException("jardiff.error.badremove", line);
231            
232                 }
233                 ignoreSet.add(sub.get(0));
234             }
235             else if (line.startsWith(MOVE_COMMAND)) {
236                 List sub = getSubpaths(line.substring(MOVE_COMMAND.length()));
237                 
238                 if (sub.size() != 2) {
239             handleException("jardiff.error.badmove", line);
240             
241                 }
242         // target of move should be the key
243
if (renameMap.put(sub.get(1), sub.get(0)) != null) {
244             // invalid move - should not move to same target twice
245
handleException("jardiff.error.badmove", line);
246         }
247             }
248             else if (line.length() > 0) {
249         handleException("jardiff.error.badcommand", line);
250     
251             }
252         }
253     }
254     
255     private void handleException(String JavaDoc errorMsg, String JavaDoc line) throws IOException {
256     try {
257         throw new IOException(getResources().getString(errorMsg) + " " + line);
258     } catch (MissingResourceException mre) {
259          System.err.println("Fatal error: " + errorMsg);
260          new Throwable JavaDoc().printStackTrace(System.err);
261          System.exit(-1);
262     }
263     }
264
265     private List getSubpaths(String JavaDoc path) {
266         int index = 0;
267         int length = path.length();
268         ArrayList sub = new ArrayList();
269         
270         while (index < length) {
271             while (index < length && Character.isWhitespace
272                        (path.charAt(index))) {
273                 index++;
274             }
275             if (index < length) {
276                 int start = index;
277                 int last = start;
278                 String JavaDoc subString = null;
279                 
280                 while (index < length) {
281                     char aChar = path.charAt(index);
282                     if (aChar == '\\' && (index + 1) < length &&
283                         path.charAt(index + 1) == ' ') {
284                         
285                         if (subString == null) {
286                             subString = path.substring(last, index);
287                         }
288                         else {
289                             subString += path.substring(last, index);
290                         }
291                         last = ++index;
292                     }
293                     else if (Character.isWhitespace(aChar)) {
294                         break;
295                     }
296                     index++;
297                 }
298                 if (last != index) {
299                     if (subString == null) {
300                         subString = path.substring(last, index);
301                     }
302                     else {
303                         subString += path.substring(last, index);
304                     }
305                 }
306                 sub.add(subString);
307             }
308         }
309         return sub;
310     }
311     
312     private void writeEntry(JarOutputStream jos, JarEntry entry,
313                             JarFile file) throws IOException {
314         writeEntry(jos, entry, file.getInputStream(entry));
315     }
316     
317     private void writeEntry(JarOutputStream jos, JarEntry entry,
318                             InputStream data) throws IOException {
319         //Create a new ZipEntry to clear the compressed size. 5079423
320
jos.putNextEntry(new ZipEntry(entry.getName()));
321         
322         // Read the entry
323
int size = data.read(newBytes);
324         
325         while (size != -1) {
326             jos.write(newBytes, 0, size);
327             size = data.read(newBytes);
328         }
329         data.close();
330     }
331 }
332
333
334
Popular Tags