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