KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > retrotranslator > transformer > FileTranslator


1 /***
2  * Retrotranslator: a Java bytecode transformer that translates Java classes
3  * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
4  *
5  * Copyright (c) 2005 - 2007 Taras Puchko
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the copyright holders nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */

32 package net.sf.retrotranslator.transformer;
33
34 import edu.emory.mathcs.backport.java.util.Queue;
35 import java.io.*;
36 import java.net.URL JavaDoc;
37 import java.util.*;
38 import net.sf.retrotranslator.runtime.impl.*;
39
40 /**
41  * @author Taras Puchko
42  */

43 class FileTranslator {
44
45     private static final String JavaDoc CLASS_DESCRIPTOR_PATH = getFileName(ClassDescriptor.class);
46     private static final String JavaDoc SIGNATURES_PATH = getFileName(ClassDescriptor.class, ClassDescriptor.SIGNATURES_NAME);
47
48     private final ClassTransformer classTransformer;
49     private final TextFileTransformer fileTransformer;
50     private final EmbeddingConverter converter;
51     private final SystemLogger logger;
52     private final SourceMask mask;
53
54     public FileTranslator(ClassTransformer classTransformer, TextFileTransformer fileTransformer,
55                           EmbeddingConverter converter, SystemLogger logger, SourceMask mask) {
56         this.classTransformer = classTransformer;
57         this.fileTransformer = fileTransformer;
58         this.converter = converter;
59         this.logger = logger;
60         this.mask = mask;
61     }
62
63     public void transform(FileContainer source, FileContainer destination) {
64         logger.log(new Message(Level.INFO, "Transforming " + source.getFileCount() + " file(s)" +
65                 (source == destination ? " in " + source : " from " + source + " to " + destination) + "."));
66         for (FileEntry entry : source.getEntries()) {
67             transform(entry, source, destination);
68         }
69         source.flush(logger);
70         logger.log(new Message(Level.INFO,
71                 "Transformation of " + source.getFileCount() + " file(s) completed successfully."));
72     }
73
74     private void transform(FileEntry entry, FileContainer source, FileContainer destination) {
75         String JavaDoc name = entry.getName();
76         if (converter != null && name.equals(SIGNATURES_PATH)) {
77             destination.putEntry(converter.convertFileName(name), transformSignatures(entry.getContent()));
78         } else if (mask.matches(name)) {
79             logger.setFile(source.getLocation(), name);
80             logger.logForFile(Level.VERBOSE, "Transformation");
81             byte[] sourceData = entry.getContent();
82             byte[] resultData = TransformerTools.isClassFile(sourceData)
83                     ? classTransformer.transform(sourceData, 0, sourceData.length)
84                     : fileTransformer.transform(sourceData, converter);
85             String JavaDoc fixedName = converter == null ? name : converter.convertFileName(name);
86             if (source != destination || sourceData != resultData || !fixedName.equals(name)) {
87                 if (!fixedName.equals(name)) destination.removeEntry(name);
88                 destination.putEntry(fixedName, resultData);
89             }
90         } else if (source != destination) {
91             destination.putEntry(entry.getName(), entry.getContent());
92         }
93     }
94
95     public void embed(FileContainer destination) {
96         Map<String JavaDoc, Boolean JavaDoc> runtimeNames = converter.getRuntimeFileNames();
97         Map<String JavaDoc, Boolean JavaDoc> concurrentNames = converter.getConcurrentFileNames();
98         if (runtimeNames.isEmpty() && concurrentNames.isEmpty()) {
99             return;
100         }
101         logger.log(new Message(Level.INFO, "Embedding backported classes"));
102         FileContainer runtimeContainer = findContainer(ClassDescriptor.class);
103         FileContainer concurrentContainer = findContainer(Queue.class);
104         while (true) {
105             if (embed(runtimeContainer, destination, runtimeNames) &&
106                     embed(concurrentContainer, destination, concurrentNames)) {
107                 break;
108             }
109         }
110         logger.log(new Message(Level.INFO, "Embedding of backported classes completed successfully."));
111     }
112
113     private boolean embed(FileContainer source, FileContainer destination, Map<String JavaDoc, Boolean JavaDoc> fileNames) {
114         boolean finished = true;
115         for (FileEntry entry : source.getEntries()) {
116             Boolean JavaDoc processed = fileNames.get(entry.getName());
117             if (Boolean.FALSE.equals(processed)) {
118                 transform(entry, source, destination);
119                 String JavaDoc name = entry.getName();
120                 fileNames.put(name, Boolean.TRUE);
121                 if (name.equals(CLASS_DESCRIPTOR_PATH)) {
122                     fileNames.put(SIGNATURES_PATH, Boolean.FALSE);
123                 }
124                 finished = false;
125             }
126         }
127         return finished;
128     }
129
130     private byte[] transformSignatures(byte[] content) {
131         try {
132             NameTranslator transformer = new NameTranslator() {
133                 protected String JavaDoc typeName(String JavaDoc s) {
134                     return converter.convertClassName(s);
135                 }
136             };
137             Properties source = new Properties();
138             source.load(new ByteArrayInputStream(content));
139             Properties target = new Properties();
140             for (Map.Entry entry : source.entrySet()) {
141                 String JavaDoc key = converter.convertClassName((String JavaDoc) entry.getKey());
142                 String JavaDoc value = transformer.declarationSignature((String JavaDoc) entry.getValue());
143                 target.put(key, value);
144             }
145             ByteArrayOutputStream stream = new ByteArrayOutputStream();
146             target.store(stream, null);
147             return stream.toByteArray();
148         } catch (IOException e) {
149             throw new RuntimeException JavaDoc(e);
150         }
151     }
152
153     private static FileContainer findContainer(Class JavaDoc aClass) {
154         String JavaDoc path = "/" + getFileName(aClass);
155         URL JavaDoc resource = aClass.getResource(path);
156         if (resource == null) {
157             throw new IllegalArgumentException JavaDoc("Location not found: " + aClass);
158         }
159         String JavaDoc url = resource.toExternalForm();
160         String JavaDoc prefix = "jar:file:";
161         String JavaDoc suffix = "!" + path;
162         if (!url.startsWith(prefix) || !url.endsWith(suffix)) {
163             throw new IllegalArgumentException JavaDoc("Not in a jar file: " + aClass);
164         }
165         File file = new File(url.substring(prefix.length(), url.length() - suffix.length()));
166         if (!file.isFile()) {
167             throw new IllegalArgumentException JavaDoc("File not found: " + file);
168         }
169         return new JarFileContainer(file);
170     }
171
172     private static String JavaDoc getFileName(Class JavaDoc aClass) {
173         return aClass.getName().replace('.', '/') + RuntimeTools.CLASS_EXTENSION;
174     }
175
176     private static String JavaDoc getFileName(Class JavaDoc aClass, String JavaDoc fileName) {
177         return aClass.getPackage().getName().replace('.', '/') + "/" + fileName;
178     }
179
180 }
181
Popular Tags