KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.*;
35 import static net.sf.retrotranslator.runtime.asm.Opcodes.*;
36 import net.sf.retrotranslator.runtime.asm.Type;
37 import net.sf.retrotranslator.runtime.impl.*;
38
39 /**
40  * @author Taras Puchko
41  */

42 class ReplacementLocator {
43
44     private static final ClassReplacement NULL = new ClassReplacement();
45
46     private final boolean advanced;
47     private final List<Backport> backports;
48     private final Map<String JavaDoc, ClassReplacement> replacements = new Hashtable<String JavaDoc, ClassReplacement>();
49
50     public ReplacementLocator(boolean advanced, List<Backport> backports) {
51         this.advanced = advanced;
52         this.backports = backports;
53     }
54
55     public ClassReplacement getReplacement(String JavaDoc className) {
56         if (className == null || className.length() == 0 || className.charAt(0) == '[') {
57             return null;
58         }
59         ClassReplacement replacement = replacements.get(className);
60         if (replacement == null) {
61             replacement = buildReplacement(className);
62             replacements.put(className, replacement);
63         }
64         return replacement == NULL ? null : replacement;
65     }
66
67     private ClassReplacement buildReplacement(String JavaDoc originalName) {
68         ClassReplacement replacement = new ClassReplacement();
69         for (Backport backport : backports) {
70             if (replacement.getUniqueTypeName() == null && originalName.equals(backport.getOriginalName())) {
71                 replacement.setUniqueTypeName(backport.getReplacementName());
72             }
73             String JavaDoc originalPrefix = backport.getOriginalPrefix();
74             if (originalPrefix == null) {
75                 continue;
76             }
77             String JavaDoc suffix = originalName;
78             if (originalPrefix.length() > 0) {
79                 if (originalName.startsWith(originalPrefix)) {
80                     suffix = originalName.substring(originalPrefix.length());
81                 } else {
82                     continue;
83                 }
84             }
85             String JavaDoc prefix = backport.getReplacementPrefix();
86             if (replacement.getUniqueTypeName() == null) {
87                 replacement.setUniqueTypeName(findUniqueName(prefix, suffix));
88             }
89             ClassDescriptor classDescriptor = getClassDescriptor(createServiceName(prefix, suffix));
90             if (classDescriptor != null) {
91                 loadFields(replacement, classDescriptor);
92                 loadMethods(replacement, classDescriptor, originalName);
93             }
94         }
95         if (replacement.isEmpty()) {
96             return NULL;
97         }
98         if (replacement.getUniqueTypeName() == null) {
99             replacement.setUniqueTypeName(originalName);
100         }
101         replacement.setReferenceTypeName(replacement.getCheckCastReplacement() != null ?
102                 Type.getReturnType(replacement.getCheckCastReplacement().getDesc()).getInternalName() :
103                 replacement.getUniqueTypeName()
104         );
105         return replacement;
106     }
107
108     private String JavaDoc findUniqueName(String JavaDoc prefix, String JavaDoc suffix) {
109         String JavaDoc uniqueName = prefix + suffix + "_";
110         if (isClassAvailable(uniqueName)) {
111             return uniqueName;
112         }
113         int index = suffix.indexOf('$');
114         if (index >= 0) {
115             uniqueName = prefix + replaceChar(suffix, index, "_$");
116             if (isClassAvailable(uniqueName)) {
117                 return uniqueName;
118             }
119             uniqueName = prefix + replaceChar(suffix, index, "_") + "_";
120             if (isClassAvailable(uniqueName)) {
121                 return uniqueName;
122             }
123         }
124         uniqueName = prefix + suffix;
125         if (isClassAvailable(uniqueName)) {
126             return uniqueName;
127         }
128         return null;
129     }
130
131     private static String JavaDoc replaceChar(String JavaDoc s, int index, String JavaDoc replacement) {
132         return s.substring(0, index) + replacement + s.substring(index + 1);
133     }
134
135     private void loadFields(ClassReplacement classReplacement, ClassDescriptor classDescriptor) {
136         for (FieldDescriptor fieldDescriptor : classDescriptor.getFieldDescriptors()) {
137             if (!fieldDescriptor.isAccess(ACC_PUBLIC) || !fieldDescriptor.isAccess(ACC_STATIC)) {
138                 continue;
139             }
140             if (!advanced && fieldDescriptor.isAnnotationPresent(Advanced.class)) {
141                 continue;
142             }
143             String JavaDoc fieldName = fieldDescriptor.getName();
144             String JavaDoc fieldDesc = fieldDescriptor.getDesc();
145             String JavaDoc key = fieldName + fieldDesc;
146             Map<String JavaDoc, MemberReplacement> replacements = classReplacement.getFieldReplacements();
147             if (replacements.containsKey(key)) {
148                 continue;
149             }
150             replacements.put(key, new MemberReplacement(classDescriptor.getName(), fieldName, fieldDesc));
151         }
152     }
153
154     private void loadMethods(ClassReplacement classReplacement, ClassDescriptor classDescriptor, String JavaDoc originalName) {
155         for (MethodDescriptor methodDescriptor : classDescriptor.getMethodDescriptors()) {
156             if (!methodDescriptor.isAccess(ACC_PUBLIC) || !methodDescriptor.isAccess(ACC_STATIC)) {
157                 continue;
158             }
159             if (!advanced && methodDescriptor.isAnnotationPresent(Advanced.class)) {
160                 continue;
161             }
162             String JavaDoc methodName = methodDescriptor.getName();
163             String JavaDoc methodDesc = methodDescriptor.getDesc();
164             String JavaDoc methodKey = methodName + methodDesc;
165             if (classReplacement.getMethodReplacements().containsKey(methodKey)) {
166                 continue;
167             }
168             MemberReplacement replacement = new MemberReplacement(classDescriptor.getName(), methodName, methodDesc);
169             classReplacement.getMethodReplacements().put(methodKey, replacement);
170             if (methodName.equals("convertConstructorArguments")) {
171                 String JavaDoc converterKey = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getArgumentTypes(methodDesc));
172                 if (!classReplacement.getConverterReplacements().containsKey(converterKey)) {
173                     classReplacement.getConverterReplacements().put(converterKey, replacement);
174                 }
175             }
176             if (classReplacement.getInstanceOfReplacement() == null &&
177                     methodName.equals("executeInstanceOfInstruction") &&
178                     methodDesc.equals(TransformerTools.descriptor(boolean.class, Object JavaDoc.class))) {
179                 classReplacement.setInstanceOfReplacement(replacement);
180             }
181             if (classReplacement.getCheckCastReplacement() == null &&
182                     methodName.equals("executeCheckCastInstruction") &&
183                     Arrays.equals(new Type[]{Type.getType(Object JavaDoc.class)}, Type.getArgumentTypes(methodDesc))) {
184                 classReplacement.setCheckCastReplacement(replacement);
185             }
186             if (methodName.equals("createInstanceBuilder")) {
187                 loadConstructor(classReplacement.getConstructorReplacements(), replacement, originalName);
188             }
189         }
190     }
191
192     private void loadConstructor(Map<String JavaDoc, ConstructorReplacement> replacements,
193                                  MemberReplacement replacement, String JavaDoc originalName) {
194         String JavaDoc constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getArgumentTypes(replacement.getDesc()));
195         if (replacements.containsKey(constructorDesc)) {
196             return;
197         }
198         String JavaDoc owner = Type.getReturnType(replacement.getDesc()).getInternalName();
199         ClassDescriptor classDescriptor = getClassDescriptor(owner);
200         if (classDescriptor == null) {
201             throw new TypeNotPresentException JavaDoc(owner, null);
202         }
203         List<MemberReplacement> arguments = new ArrayList<MemberReplacement>();
204         MemberReplacement initializer = null;
205         for (MethodDescriptor descriptor : classDescriptor.getMethodDescriptors()) {
206             if (isArgument(descriptor)) {
207                 arguments.add(new MemberReplacement(owner, descriptor.getName(), descriptor.getDesc()));
208             } else if (isInitializer(descriptor, originalName)) {
209                 initializer = new MemberReplacement(owner, descriptor.getName(), descriptor.getDesc());
210             }
211         }
212         Collections.sort(arguments, new Comparator<MemberReplacement>() {
213             public int compare(MemberReplacement o1, MemberReplacement o2) {
214                 return o1.getName().compareTo(o2.getName());
215             }
216         });
217         List<Type> types = new ArrayList<Type>();
218         for (MemberReplacement argument : arguments) {
219             types.add(Type.getReturnType(argument.getDesc()));
220         }
221         MemberReplacement constructor = new MemberReplacement(originalName, RuntimeTools.CONSTRUCTOR_NAME,
222                 Type.getMethodDescriptor(Type.VOID_TYPE, types.toArray(new Type[0])));
223         replacements.put(constructorDesc, new ConstructorReplacement(replacement,
224                 arguments.toArray(new MemberReplacement[0]), constructor, initializer));
225     }
226
227     private static boolean isArgument(MethodDescriptor descriptor) {
228         if (!descriptor.getName().startsWith("argument")) return false;
229         if (Type.getReturnType(descriptor.getDesc()) == Type.VOID_TYPE) return false;
230         if (Type.getArgumentTypes(descriptor.getDesc()).length > 0) return false;
231         return descriptor.isAccess(ACC_PUBLIC) && !descriptor.isAccess(ACC_STATIC);
232     }
233
234     private static boolean isInitializer(MethodDescriptor descriptor, String JavaDoc originalName) {
235         if (!descriptor.getName().equals("initialize")) return false;
236         if (Type.getReturnType(descriptor.getDesc()) != Type.VOID_TYPE) return false;
237         Type[] types = Type.getArgumentTypes(descriptor.getDesc());
238         if (types.length != 1) return false;
239         if (!types[0].getInternalName().equals(originalName)) return false;
240         return descriptor.isAccess(ACC_PUBLIC) && !descriptor.isAccess(ACC_STATIC);
241     }
242
243     private static String JavaDoc createServiceName(String JavaDoc prefix, String JavaDoc suffix) {
244         int index = suffix.lastIndexOf('/');
245         return prefix + suffix.substring(0, index + 1) + '_' + suffix.substring(index + 1);
246     }
247
248     private boolean isClassAvailable(String JavaDoc internalName) {
249         return getClassDescriptor(internalName) != null;
250     }
251
252     private ClassDescriptor getClassDescriptor(String JavaDoc internalName) {
253         byte[] bytecode = RuntimeTools.readResourceToByteArray(
254                 ReplacementLocator.class, '/' + internalName + RuntimeTools.CLASS_EXTENSION);
255         if (bytecode == null) return null;
256         ClassDescriptor descriptor = new ClassDescriptor(ReplacementLocator.class, bytecode);
257         return !advanced && descriptor.isAnnotationPresent(Advanced.class) ? null : descriptor;
258     }
259
260 }
261
Popular Tags