1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jdo.impl.enhancer;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24
25 import java.util.zip.CRC32;
26 import java.util.zip.ZipEntry;
27 import java.util.zip.ZipInputStream;
28 import java.util.zip.ZipOutputStream;
29
30
31 /***
32 * This is a helper-class to perform some useful operations outside a
33 * byte code enhancer and delegate the real work to the enhancer.
34 */
35 public class ClassFileEnhancerHelper
36 {
37 /***
38 * Enhances a classfile.
39 *
40 * @param enhancer The enhancer to delegate the work to.
41 * @param in The input stream with the Java class.
42 * @param out The output stream to write the enhanced class to.
43 *
44 * @return Has the input stream been enhanced?
45 *
46 * @exception EnhancerUserException If something went wrong.
47 * @exception EnhancerFatalError If something went wrong.
48 *
49 * @see ClassFileEnhancer#enhanceClassFile
50 */
51 static public boolean enhanceClassFile(ClassFileEnhancer enhancer,
52 InputStream in,
53 OutputStream out)
54 throws EnhancerUserException,
55 EnhancerFatalError
56 {
57 return enhancer.enhanceClassFile(in, new OutputStreamWrapper(out));
58 }
59
60 /***
61 * Enhances a zip file. The zip file is given as a uip input stream.
62 * It's entries are read and - if necessary - individually enhanced.
63 * The output stream has the same compressÌon (if any) as the input
64 * stream.
65 *
66 * @param enhancer The enhancer.
67 * @param zip_in The zip input stream.
68 * @param zip_out The zip output stream.
69 *
70 * @return <code>true</code> if at least one entry of the zip file has
71 * been enhanced, <code>false</code> otherwise.
72 *
73 * @exception EnhancerUserException If something went wrong.
74 * @exception EnhancerFatalError If something went wrong.
75 *
76 * @see ClassFileEnhancer#enhanceClassFile
77 */
78 static public boolean enhanceZipFile(ClassFileEnhancer enhancer,
79 ZipInputStream zip_in,
80 ZipOutputStream zip_out)
81 throws EnhancerUserException,
82 EnhancerFatalError
83 {
84 boolean enhanced = false;
85 try {
86 CRC32 crc32 = new CRC32();
87 ZipEntry entry;
88 while ((entry = zip_in.getNextEntry()) != null) {
89 InputStream in = zip_in;
90 final ZipEntry out_entry = new ZipEntry(entry);
91
92
93 if (isClassFileEntry(entry)) {
94
95
96
97
98
99 in = openZipEntry(zip_in);
100 in.mark(Integer.MAX_VALUE);
101 final ByteArrayOutputStream tmp
102 = new ByteArrayOutputStream();
103 if (enhancer.enhanceClassFile(in, tmp)) {
104 enhanced = true;
105 final byte[] bytes = tmp.toByteArray();
106 tmp.close();
107 in.close();
108 modifyZipEntry(out_entry, bytes, crc32);
109 in = new ByteArrayInputStream(bytes);
110 } else {
111
112 in.reset();
113 }
114 }
115
116
117 zip_out.putNextEntry(out_entry);
118 copyZipEntry(in, zip_out);
119 zip_out.closeEntry();
120
121 if (in != zip_in) {
122 in.close();
123 }
124 }
125 } catch (IOException ex) {
126 throw new EnhancerFatalError(ex);
127 }
128
129 return enhanced;
130 }
131
132 /***
133 * Copies a zip entry from one stream to another.
134 *
135 * @param in The inout stream.
136 * @param out The output stream.
137 *
138 * @exception IOException If the stream access failed.
139 */
140 static private void copyZipEntry(InputStream in,
141 OutputStream out)
142 throws IOException
143 {
144 int b;
145 while ((in.available() > 0) && (b = in.read()) > -1) {
146 out.write(b);
147 }
148 }
149
150 /***
151 * Opens the next zip entry of a zip input stream and copies it to
152 * a <code>java.io.ByteArrayOutputStream</code>. It's byte array is made
153 * available via an <code>java.io.ByteArrayInputStream</code> which is
154 * returned.
155 *
156 * @param in The zip input stream.
157 *
158 * @return The newly created input stream with the next zip entry.
159 *
160 * @exception IOException If an I/O operation failed.
161 */
162 static private InputStream openZipEntry(ZipInputStream in)
163 throws IOException
164 {
165 ByteArrayOutputStream out = new ByteArrayOutputStream();
166 copyZipEntry(in, out);
167
168 return new ByteArrayInputStream(out.toByteArray());
169 }
170
171 /***
172 * Modifies the given zip entry so that it can be added to zip file.
173 * The given zip entry represents an enhanced class, so the zip entry
174 * has to get the correct size and checksum (but only if the entry won't
175 * be compressed).
176 *
177 * @param entry The zip entry to modify.
178 * @param bytes The uncompressed byte representation of the classfile.
179 * @param crc32 The checksum evaluator.
180 */
181 private static void modifyZipEntry(ZipEntry entry,
182 byte [] bytes,
183 CRC32 crc32)
184 {
185 entry.setSize(bytes.length);
186 if (entry.getMethod() == 0) {
187
188 crc32.reset();
189 crc32.update(bytes);
190 entry.setCrc(crc32.getValue());
191 entry.setCompressedSize(bytes.length);
192 }
193 }
194
195 /***
196 * Determines if a given entry represents a classfile.
197 *
198 * @return Does the given entry represent a classfile?
199 */
200 private static boolean isClassFileEntry(ZipEntry entry)
201 {
202 return entry.getName().endsWith(".class");
203 }
204 }