KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > compiere > tools > ClassVersionLimiter


1 package org.compiere.tools;
2
3 import java.io.*;
4 import java.util.*;
5 import java.util.zip.*;
6 import java.util.jar.*;
7
8 /**
9  * <b>JDK 1.4 Beta 2 won't work with JBuilder</b>
10  * <p>
11  * When compiling a ".java"-file the compiler puts format version info in the
12  * first bytes of the resulting class file. In Merlin (JDK 1.4)
13  * Beta2 Sun has changed the version info of many of the JDK's class files
14  * to '48.0' while previous JDKs used versions up to '46.0'.
15  * I do not know if there actually are any differences in the class file format.
16  * There are almost certainly some minor changes. Unfortunately the JDK 1.4 release
17  * notes fail to adress this incompatibility. If anyone knows some details please e-mail me.
18  * The JDK tools provided with the Beta release can all deal with version '48.0' class files.
19  * But if you use other tools (like the Borland compiler), they will probably refuse to load the JDK's class files.
20  * <p>
21  * <b>Patch the JDK 1.4 Beta 2 release</b>
22  * <p>
23  * To be able to play around with Merlin Beta 2 using JBuilder5, I wrote a little hack,
24  * that patches all jar files in the JDK to a version of max. '46.0'.
25  * I got my current project running without noticing any problems.
26  * <p>
27  * THIS IS A HACK. IT WILL ALMOST CERTAINLY BREAK SOME CODE. USE AT YOUR OWN RISK.
28  * If in any part of your application you get some strange errors,
29  * especially related to class loading, this patch may well be the reason.
30  * Please E-Mail me with details about where the problems occur.
31  * <p>
32  * If your JDK's root directory isn't "D:\jdk1.4b2"
33  * then edit the path in the code (one of the very first lines).
34  * Be sure to have write access to the JDK sub-directories.
35  * <p>
36  * Run the resulting class. It will patch all class files in all jar files
37  * in your JDK to have a version info of '46.0' at max.
38  * The original jar-files will get copied to .BAK-files.
39  * <p>
40  * java -cp %COMPIERE_HOME%/lib/CServer.jar org.compiere.tools.ClassVersionLimiter
41  *
42  * @author Stephen Kelvin - with minor changes by Jorg Janke
43  * @see http://www.StephenKelvin.de/MerlinPatch/
44  * @version $Id: ClassVersionLimiter.java,v 1.3 2001/11/14 02:49:29 jjanke Exp $
45  */

46 public class ClassVersionLimiter
47 {
48     /**
49      * Run it
50      */

51     public static void main(String JavaDoc[] args)
52     {
53         ClassVersionLimiter classVersionLimiter = new ClassVersionLimiter("D:/j2sdk1.4b3p", 46, 0);
54     } // main
55

56     /** Version Key */
57     private long _maxAllowedVersion;
58
59     /** Log file */
60     private PrintWriter m_out = null;
61
62
63     /**
64      * Constructor
65      */

66     public ClassVersionLimiter(String JavaDoc rootDirectory, int mainVersion, int minorVersion)
67     {
68         _maxAllowedVersion = mainVersion * 65536 + minorVersion;
69
70         // Create Log file
71
try
72         {
73             File logFile = new File(rootDirectory + File.separator + "patchJar.log");
74             m_out = new PrintWriter(new FileOutputStream(logFile), true); // autoFlush
75
System.out.println("Log=" + logFile.getAbsolutePath());
76         }
77         catch (Exception JavaDoc e)
78         {
79             System.err.println("Cannot write log");
80             e.printStackTrace(System.err);
81             System.exit(1);
82         }
83
84         // Change jars
85
File root = new File(rootDirectory);
86         search(root);
87     } // ClassVersionLimiter
88

89     /**
90      * Search all for all jars in a directory and recursively go through sub-directories
91      */

92     private void search(File dir)
93     {
94         dir.listFiles (new FileFilter()
95         {
96             public boolean accept(File pathname)
97             {
98                 if (pathname.getName().endsWith(".jar"))
99                     checkJar(pathname);
100                 if (pathname.isDirectory())
101                     search(pathname);
102                 return false;
103             }
104         });
105     } // search
106

107     /**
108      * Check the Jar
109      */

110     private void checkJar(File file)
111     {
112         byte[] header = new byte[8];
113         long maxVersion = 0;
114         boolean foundClassFiles = false;
115         try
116         {
117             JarFile jarFile = new JarFile(file);
118             Enumeration entries = jarFile.entries();
119             while (entries.hasMoreElements())
120             {
121                 JarEntry entry = (JarEntry) entries.nextElement();
122                 if (entry.getName().endsWith(".class"))
123                 {
124                     foundClassFiles = true;
125                     InputStream stream = jarFile.getInputStream(entry);
126                     stream.read(header);
127                     int mainVersion = header[6] * 256 + header[7];
128                     int minorVersion = header[4] * 256 + header[5];
129                     long version = mainVersion * 65536 + minorVersion;
130                     if (version > maxVersion)
131                         maxVersion = version;
132                 }
133             }
134             jarFile.close();
135             if (foundClassFiles && maxVersion > _maxAllowedVersion)
136             {
137                 patchJar(file);
138             }
139         }
140         catch (Exception JavaDoc e)
141         {
142             log ("checkJar", e);
143         }
144     } // checkJar
145

146     /**
147      * Patch the Jar
148      */

149     private void patchJar(File file)
150     {
151         log ("Patching " + file, null);
152         try
153         {
154             final int MAX_ENTRY_SIZE = 1024 * 1024; // 1 MB
155
byte[] classBytes = new byte[MAX_ENTRY_SIZE];
156             File newFile = new File(file.getAbsolutePath() + ".NEW");
157
158             CRC32 crc32 = new CRC32();
159             JarFile oldJarFile = new JarFile(file);
160             Manifest manifest = oldJarFile.getManifest();
161             FileOutputStream outputStream = new FileOutputStream(newFile);
162             JarOutputStream jarOutput = new JarOutputStream(outputStream, manifest);
163             Enumeration entries = oldJarFile.entries();
164
165             while (entries.hasMoreElements())
166             {
167                 JarEntry oldEntry = (JarEntry) entries.nextElement();
168                 JarEntry newEntry = (JarEntry) oldEntry.clone();
169                 System.out.print("."); // indicate progress, don't log
170
if (oldEntry.getName().equals("META-INF/MANIFEST.MF"))
171                     continue;
172
173                 // copy into classBytes
174
InputStream in = oldJarFile.getInputStream(oldEntry);
175                 int totalLen = 0;
176                 int readLen = 0;
177                 do
178                 {
179                     totalLen += readLen;
180                     readLen = in.read(classBytes, totalLen, MAX_ENTRY_SIZE - totalLen);
181                 } while(readLen > 0);
182                 if (totalLen == MAX_ENTRY_SIZE)
183                 {
184                     log ("ERROR= patchJAR: MAX_ENTRY_SIZE too small - " + MAX_ENTRY_SIZE, null);
185                     return;
186                 }
187
188                 if (totalLen > 0 && oldEntry.getName().endsWith(".class"))
189                 {
190                     int mainVersion = classBytes[6] * 256 + classBytes[7];
191                     int minorVersion = classBytes[4] * 256 + classBytes[5];
192                     long version = mainVersion * 65536 + minorVersion;
193                     // we need to patch this class file
194
if (version > _maxAllowedVersion)
195                     {
196                         log (" - " + oldEntry.getName(), null);
197                         mainVersion = (int) _maxAllowedVersion / 65536;
198                         minorVersion = (int) _maxAllowedVersion % 65536;
199                         classBytes[4] = (byte) (minorVersion / 256);
200                         classBytes[5] = (byte) (minorVersion % 256);
201                         classBytes[6] = (byte) (mainVersion / 256);
202                         classBytes[7] = (byte) (mainVersion % 256);
203
204                         crc32.reset();
205                         crc32.update(classBytes, 0, totalLen);
206                         newEntry.setCrc(crc32.getValue());
207                         // The compressed size can differ if the uncompressed data is changed. -1 means unknown.
208
newEntry.setCompressedSize(-1);
209                     }
210                 }
211                 jarOutput.putNextEntry(newEntry);
212                 if (totalLen > 0)
213                     jarOutput.write(classBytes, 0, totalLen);
214                 jarOutput.closeEntry();
215             }
216             jarOutput.close();
217             outputStream.close();
218             oldJarFile.close();
219             // done with entries
220
log ("", null);
221
222             //
223
File bakFile = new File(file.getAbsolutePath() + ".BAK");
224             if (!file.renameTo(bakFile))
225             {
226                 log ("ERROR= Cannot rename " + file + " to " + bakFile + ". EXITING.", null);
227                 System.exit(99);
228             }
229             if(!newFile.renameTo(file))
230             {
231                 log ("ERROR= Cannot rename " + newFile + " to " + file + ". EXITING.", null);
232                 System.exit(99);
233             }
234         }
235         catch (Exception JavaDoc e)
236         {
237             log ("patchJar", e);
238         }
239     } // patchJar
240

241     /**
242      * Log entries in file
243      */

244     private void log (String JavaDoc message, Exception JavaDoc e)
245     {
246         if (e == null)
247         {
248             System.out.println(message);
249             m_out.println(message);
250         }
251         else
252         {
253             System.err.print("ERROR= ");
254             System.err.println(message);
255             e.printStackTrace(System.err);
256             //
257
m_out.print("ERROR= ");
258             m_out.println(message);
259             e.printStackTrace(m_out);
260         }
261     } // log
262

263 } // ClassVersionLimiter
264

265
Popular Tags