KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > update > internal > jarprocessor > JarProcessor


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM - Initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.update.internal.jarprocessor;
12
13 import java.io.*;
14 import java.util.*;
15 import java.util.jar.*;
16
17 /**
18  * @author aniefer@ca.ibm.com
19  *
20  */

21 public class JarProcessor {
22     private List steps = new ArrayList();
23     private String JavaDoc workingDirectory = ""; //$NON-NLS-1$
24
private int depth = -1;
25     private boolean verbose = false;
26     private boolean processAll = false;
27     private LinkedList containingInfs = new LinkedList();
28
29     static public JarProcessor getUnpackProcessor(Properties properties) {
30         if (!canPerformUnpack())
31             throw new UnsupportedOperationException JavaDoc();
32         JarProcessor processor = new JarProcessor();
33         processor.addProcessStep(new UnpackStep(properties));
34         return processor;
35     }
36
37     static public JarProcessor getPackProcessor(Properties properties) {
38         if (!canPerformPack())
39             throw new UnsupportedOperationException JavaDoc();
40         JarProcessor processor = new JarProcessor();
41         processor.addProcessStep(new PackStep(properties));
42         return processor;
43     }
44
45     static public boolean canPerformPack() {
46         return PackStep.canPack();
47     }
48
49     static public boolean canPerformUnpack() {
50         return UnpackStep.canUnpack();
51     }
52
53     public String JavaDoc getWorkingDirectory() {
54         return workingDirectory;
55     }
56
57     public void setWorkingDirectory(String JavaDoc dir) {
58         if(dir != null)
59             workingDirectory = dir;
60     }
61     
62     public void setVerbose(boolean verbose) {
63         this.verbose = verbose;
64     }
65     
66     public void setProcessAll(boolean all){
67         this.processAll = all;
68     }
69
70     public void addProcessStep(IProcessStep step) {
71         steps.add(step);
72     }
73
74     public void clearProcessSteps() {
75         steps.clear();
76     }
77
78     /**
79      * Recreate a jar file. The replacements map specifies entry names to be replaced, the replacements are
80      * expected to be found in directory.
81      *
82      * @param jar - The input jar
83      * @param outputJar - the output
84      * @param replacements - map of entryName -> new entryName
85      * @param directory - location to find file for new entryName
86      * @throws IOException
87      */

88     private void recreateJar(JarFile jar, JarOutputStream outputJar, Map replacements, File directory, Properties inf) throws IOException {
89         InputStream in = null;
90         boolean marked = false;
91         try {
92             Enumeration entries = jar.entries();
93             for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
94                 File replacement = null;
95                 JarEntry newEntry = null;
96                 if (replacements.containsKey(entry.getName())) {
97                     String JavaDoc name = (String JavaDoc) replacements.get(entry.getName());
98                     replacement = new File(directory, name);
99                     if (name != null) {
100                         if (replacement.exists()) {
101                             try {
102                                 in = new BufferedInputStream(new FileInputStream(replacement));
103                                 newEntry = new JarEntry(name);
104                             } catch (Exception JavaDoc e) {
105                                 if (verbose) {
106                                     e.printStackTrace();
107                                     System.out.println("Warning: Problem reading " +replacement.getPath() + ", using " + jar.getName() + File.separator + entry.getName() + " instead.");
108                                 }
109                             }
110                         } else if (verbose) {
111                             System.out.println("Warning: " + replacement.getPath() + " not found, using " + jar.getName() + File.separator + entry.getName() + " instead.");
112                         }
113                     }
114                 }
115                 if (newEntry == null) {
116                     try {
117                         in = new BufferedInputStream(jar.getInputStream(entry));
118                         newEntry = new JarEntry(entry.getName());
119                     } catch( Exception JavaDoc e ) {
120                         if(verbose) {
121                             e.printStackTrace();
122                             System.out.println("ERROR: problem reading " + entry.getName() + " from " + jar.getName());
123                         }
124                         continue;
125                     }
126                 }
127                 newEntry.setTime(entry.getTime());
128                 outputJar.putNextEntry(newEntry);
129                 if (entry.getName().equals(Utils.MARK_FILE_NAME)) {
130                     //The eclipse.inf file was read in earlier, don't need to reread it, just write it out now
131
Utils.storeProperties(inf, outputJar);
132                     marked = true;
133                 } else {
134                     Utils.transferStreams(in, outputJar, false);
135                 }
136                 outputJar.closeEntry();
137                 in.close();
138
139                 //delete the nested jar file
140
if (replacement != null) {
141                     replacement.delete();
142                 }
143             }
144             if (!marked) {
145                 JarEntry entry = new JarEntry(Utils.MARK_FILE_NAME);
146                 outputJar.putNextEntry(entry);
147                 Utils.storeProperties(inf, outputJar);
148                 outputJar.closeEntry();
149             }
150         } finally {
151             Utils.close(outputJar);
152             Utils.close(jar);
153             Utils.close(in);
154         }
155     }
156
157     private String JavaDoc recursionEffect(String JavaDoc entryName) {
158         String JavaDoc result = null;
159         for (Iterator iter = steps.iterator(); iter.hasNext();) {
160             IProcessStep step = (IProcessStep) iter.next();
161
162             result = step.recursionEffect(entryName);
163             if (result != null)
164                 entryName = result;
165         }
166         return result;
167     }
168
169     private void extractEntries(JarFile jar, File tempDir, Map data, Properties inf) throws IOException {
170         if(inf != null ) {
171             //skip if excluding children
172
if(inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN)){
173                 String JavaDoc excludeChildren = inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN);
174                 if( Boolean.valueOf(excludeChildren).booleanValue() )
175                     if(verbose){
176                         for(int i = 0; i <= depth; i++)
177                             System.out.print(" "); //$NON-NLS-1$
178
System.out.println("Children of " + jar.getName() + "are excluded from processing.");
179                     }
180                     return;
181             }
182         }
183         
184         Enumeration entries = jar.entries();
185         if (entries.hasMoreElements()) {
186             for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
187                 String JavaDoc name = entry.getName();
188                 String JavaDoc newName = recursionEffect(name);
189                 if (newName != null) {
190                     if(verbose){
191                         for(int i = 0; i <= depth; i++)
192                             System.out.print(" "); //$NON-NLS-1$
193
System.out.println("Processing nested file: " + name); //$NON-NLS-1$
194
}
195                     //extract entry to temp directory
196
File extracted = new File(tempDir, name);
197                     File parentDir = extracted.getParentFile();
198                     if (!parentDir.exists())
199                         parentDir.mkdirs();
200
201                     InputStream in = null;
202                     OutputStream out = null;
203                     try {
204                         in = jar.getInputStream(entry);
205                         out = new BufferedOutputStream(new FileOutputStream(extracted));
206                         Utils.transferStreams(in, out, true); //this will close both streams
207
} finally {
208                         Utils.close(in);
209                         Utils.close(out);
210                     }
211                     extracted.setLastModified(entry.getTime());
212
213                     //recurse
214
containingInfs.addFirst(inf);
215                     String JavaDoc dir = getWorkingDirectory();
216                     setWorkingDirectory(parentDir.getCanonicalPath());
217                     File result = processJar(extracted);
218
219                     newName = name.substring(0, name.length() - extracted.getName().length()) + result.getName();
220                     data.put(name, newName);
221
222                     setWorkingDirectory(dir);
223                     containingInfs.removeFirst();
224
225                     //delete the extracted item leaving the recursion result
226
if (!name.equals(newName))
227                         extracted.delete();
228                 }
229             }
230         }
231     }
232
233     private File preProcess(File input, File tempDir) {
234         File result = null;
235         for (Iterator iter = steps.iterator(); iter.hasNext();) {
236             IProcessStep step = (IProcessStep) iter.next();
237             result = step.preProcess(input, tempDir, containingInfs);
238             if (result != null)
239                 input = result;
240         }
241         return input;
242     }
243
244     private File postProcess(File input, File tempDir) {
245         File result = null;
246         for (Iterator iter = steps.iterator(); iter.hasNext();) {
247             IProcessStep step = (IProcessStep) iter.next();
248             result = step.postProcess(input, tempDir, containingInfs);
249             if (result != null)
250                 input = result;
251         }
252         return input;
253     }
254
255     private void adjustInf(File input, Properties inf) {
256         for (Iterator iter = steps.iterator(); iter.hasNext();) {
257             IProcessStep step = (IProcessStep) iter.next();
258             step.adjustInf(input, inf, containingInfs);
259         }
260     }
261
262     public File processJar(File input) throws IOException {
263         ++depth;
264         long lastModified = input.lastModified();
265         File workingDir = new File(getWorkingDirectory());
266         if (!workingDir.exists())
267             workingDir.mkdirs();
268
269         boolean skip = Utils.shouldSkipJar(input, processAll, verbose);
270         if (depth == 0 && verbose) {
271             if (skip)
272                 System.out.println("Skipping " + input.getPath()); //$NON-NLS-1$
273
else {
274                 System.out.print("Running "); //$NON-NLS-1$
275
for (Iterator iter = steps.iterator(); iter.hasNext();) {
276                     IProcessStep step = (IProcessStep) iter.next();
277                     System.out.print(step.getStepName() + " "); //$NON-NLS-1$
278
}
279                 System.out.println("on " + input.getPath()); //$NON-NLS-1$
280
}
281         }
282
283         if (skip) {
284             //This jar was not marked as conditioned, and we are only processing conditioned jars, so do nothing
285
--depth;
286             return input;
287         }
288
289         //pre
290
File workingFile = preProcess(input, workingDir);
291
292         //Extract entries from jar and recurse on them
293
File tempDir = null;
294         if (depth == 0) {
295             tempDir = new File(workingDir, "temp." + workingFile.getName()); //$NON-NLS-1$
296
} else {
297             File parent = workingDir.getParentFile();
298             tempDir = new File(parent, "temp_" + depth + '_' + workingFile.getName()); //$NON-NLS-1$
299
}
300
301         JarFile jar = new JarFile(workingFile, false);
302         Map replacements = new HashMap();
303         Properties inf = Utils.getEclipseInf(workingFile, verbose);
304         extractEntries(jar, tempDir, replacements, inf);
305
306         if (inf != null)
307             adjustInf(workingFile, inf);
308
309         //Recreate the jar with replacements.
310
//TODO: This is not strictly necessary if we didn't change the inf file and didn't change any content
311
File tempJar = null;
312         tempJar = new File(tempDir, workingFile.getName());
313         File parent = tempJar.getParentFile();
314         if (!parent.exists())
315             parent.mkdirs();
316         JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
317         recreateJar(jar, jarOut, replacements, tempDir, inf);
318
319         jar.close();
320         if (tempJar != null) {
321             if (!workingFile.equals(input)) {
322                 workingFile.delete();
323             }
324             workingFile = tempJar;
325         }
326
327         //post
328
File result = postProcess(workingFile, workingDir);
329         
330         //have to normalize after the post steps
331
normalize(result, workingDir);
332         
333         if (!result.equals(workingFile) && !workingFile.equals(input))
334             workingFile.delete();
335         if (!result.getParentFile().equals(workingDir)) {
336             File finalFile = new File(workingDir, result.getName());
337             if (finalFile.exists())
338                 finalFile.delete();
339             result.renameTo(finalFile);
340             result = finalFile;
341         }
342
343         if (tempDir.exists())
344             Utils.clear(tempDir);
345
346         result.setLastModified(lastModified);
347         --depth;
348         return result;
349     }
350     
351     private void normalize(File input, File workingDirectory) {
352         if(input.getName().endsWith(Utils.PACKED_SUFFIX)) {
353             //not a jar
354
return;
355         }
356         try {
357             File tempJar = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
358
JarFile jar = null;
359             try {
360                 jar = new JarFile(input, false);
361             } catch (JarException e) {
362                 //not a jar
363
return ;
364             }
365             JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
366             InputStream in = null;
367             try {
368                 Enumeration entries = jar.entries();
369                 for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
370                     JarEntry newEntry = new JarEntry(entry.getName());
371                     newEntry.setTime(entry.getTime());
372                     in = new BufferedInputStream(jar.getInputStream(entry));
373                     jarOut.putNextEntry(newEntry);
374                     Utils.transferStreams(in, jarOut, false);
375                     jarOut.closeEntry();
376                     in.close();
377                 }
378             } finally {
379                 Utils.close(jarOut);
380                 Utils.close(jar);
381                 Utils.close(in);
382             }
383             tempJar.setLastModified(input.lastModified());
384             input.delete();
385             tempJar.renameTo(input);
386         } catch (IOException e) {
387             if (verbose) {
388                 System.out.println("Error normalizing jar " + input.getName()); //$NON-NLS-1$
389
e.printStackTrace();
390             }
391         }
392     }
393 }
394
Popular Tags