001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package net.sf.cglib.transform;
017:
018: import java.io.*;
019: import java.net.MalformedURLException;
020: import java.util.*;
021: import java.util.zip.*;
022: import java.util.zip.ZipEntry;
023: import java.util.zip.ZipInputStream;
024:
025: import net.sf.cglib.core.*;
026: import org.apache.tools.ant.*;
027: import org.apache.tools.ant.BuildException;
028: import org.apache.tools.ant.ProjectComponent;
029: import org.objectweb.asm.*;
030:
031: abstract public class AbstractTransformTask extends AbstractProcessTask {
032: private static final int ZIP_MAGIC = 0x504B0304;
033:
034: private static final int CLASS_MAGIC = 0xCAFEBABE;
035:
036: private boolean verbose;
037:
038: public void setVerbose(boolean verbose) {
039: this .verbose = verbose;
040: }
041:
042: /**
043: * returns transformation for source class
044: *
045: * @param classInfo
046: * class information
047: * class name := classInfo[ 0 ]
048: * super class name := classInfo[ 1 ]
049: * interfaces := classInfo[ >1 ]
050: */
051: abstract protected ClassTransformer getClassTransformer(
052: String[] classInfo);
053:
054: protected Attribute[] attributes() {
055: return null;
056: }
057:
058: protected void processFile(File file) throws Exception {
059:
060: if (isClassFile(file)) {
061:
062: processClassFile(file);
063:
064: } else if (isJarFile(file)) {
065:
066: processJarFile(file);
067:
068: } else {
069:
070: log("ignoring " + file.toURL(), Project.MSG_WARN);
071:
072: }
073: }
074:
075: /**
076: * @param file
077: * @throws Exception
078: * @throws FileNotFoundException
079: * @throws IOException
080: * @throws MalformedURLException
081: */
082: private void processClassFile(File file) throws Exception,
083: FileNotFoundException, IOException, MalformedURLException {
084:
085: ClassReader reader = getClassReader(file);
086: String name[] = ClassNameReader.getClassInfo(reader);
087: ClassWriter w = new DebuggingClassWriter(true);
088: ClassTransformer t = getClassTransformer(name);
089: if (t != null) {
090:
091: if (verbose) {
092: log("processing " + file.toURL());
093: }
094: new TransformingClassGenerator(new ClassReaderGenerator(
095: getClassReader(file), attributes(), skipDebug()), t)
096: .generateClass(w);
097: FileOutputStream fos = new FileOutputStream(file);
098: try {
099: fos.write(w.toByteArray());
100: } finally {
101: fos.close();
102: }
103:
104: }
105:
106: }
107:
108: protected boolean skipDebug() {
109: return false;
110: }
111:
112: private static ClassReader getClassReader(File file)
113: throws Exception {
114: InputStream in = new BufferedInputStream(new FileInputStream(
115: file));
116: try {
117: ClassReader r = new ClassReader(in);
118: return r;
119: } finally {
120: in.close();
121: }
122:
123: }
124:
125: protected boolean isClassFile(File file) throws IOException {
126:
127: return checkMagic(file, CLASS_MAGIC);
128:
129: }
130:
131: protected void processJarFile(File file) throws Exception {
132:
133: if (verbose) {
134: log("processing " + file.toURL());
135: }
136:
137: File tempFile = File.createTempFile(file.getName(), null,
138: new File(file.getAbsoluteFile().getParent()));
139: try {
140:
141: ZipInputStream zip = new ZipInputStream(
142: new FileInputStream(file));
143: try {
144: FileOutputStream fout = new FileOutputStream(tempFile,
145: false);
146: try {
147: ZipOutputStream out = new ZipOutputStream(fout);
148:
149: ZipEntry entry;
150: while ((entry = zip.getNextEntry()) != null) {
151:
152: byte bytes[] = getBytes(zip);
153:
154: if (!entry.isDirectory()) {
155:
156: DataInputStream din = new DataInputStream(
157: new ByteArrayInputStream(bytes));
158:
159: if (din.readInt() == CLASS_MAGIC) {
160:
161: bytes = process(bytes);
162:
163: } else {
164: if (verbose) {
165: log("ignoring " + entry.toString());
166: }
167: }
168: }
169:
170: ZipEntry outEntry = new ZipEntry(entry
171: .getName());
172: outEntry.setMethod(entry.getMethod());
173: outEntry.setComment(entry.getComment());
174: outEntry.setSize(bytes.length);
175:
176: if (outEntry.getMethod() == ZipEntry.STORED) {
177: CRC32 crc = new CRC32();
178: crc.update(bytes);
179: outEntry.setCrc(crc.getValue());
180: outEntry.setCompressedSize(bytes.length);
181: }
182: out.putNextEntry(outEntry);
183: out.write(bytes);
184: out.closeEntry();
185: zip.closeEntry();
186:
187: }
188: out.close();
189: } finally {
190: fout.close();
191: }
192: } finally {
193: zip.close();
194: }
195:
196: if (file.delete()) {
197:
198: File newFile = new File(tempFile.getAbsolutePath());
199:
200: if (!newFile.renameTo(file)) {
201: throw new IOException("can not rename " + tempFile
202: + " to " + file);
203: }
204:
205: } else {
206: throw new IOException("can not delete " + file);
207: }
208:
209: } finally {
210:
211: tempFile.delete();
212:
213: }
214:
215: }
216:
217: /**
218: * @param bytes
219: * @return
220: * @throws IOException
221: * @throws Exception
222: */
223: private byte[] process(byte[] bytes) throws Exception {
224:
225: ClassReader reader = new ClassReader(new ByteArrayInputStream(
226: bytes));
227: String name[] = ClassNameReader.getClassInfo(reader);
228: ClassWriter w = new DebuggingClassWriter(true);
229: ClassTransformer t = getClassTransformer(name);
230: if (t != null) {
231: if (verbose) {
232: log("processing " + name[0]);
233: }
234: new TransformingClassGenerator(new ClassReaderGenerator(
235: new ClassReader(new ByteArrayInputStream(bytes)),
236: attributes(), skipDebug()), t).generateClass(w);
237: ByteArrayOutputStream out = new ByteArrayOutputStream();
238: out.write(w.toByteArray());
239: return out.toByteArray();
240: }
241: return bytes;
242: }
243:
244: /**
245: * @param zip
246: * @return
247: * @throws IOException
248: */
249: private byte[] getBytes(ZipInputStream zip) throws IOException {
250:
251: ByteArrayOutputStream bout = new ByteArrayOutputStream();
252: InputStream in = new BufferedInputStream(zip);
253: int b;
254: while ((b = in.read()) != -1) {
255: bout.write(b);
256: }
257: return bout.toByteArray();
258: }
259:
260: private boolean checkMagic(File file, long magic)
261: throws IOException {
262: DataInputStream in = new DataInputStream(new FileInputStream(
263: file));
264: try {
265: int m = in.readInt();
266: return magic == m;
267: } finally {
268: in.close();
269: }
270: }
271:
272: protected boolean isJarFile(File file) throws IOException {
273: return checkMagic(file, ZIP_MAGIC);
274: }
275:
276: }
|