KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > jdt > ByteCodeCompiler


1 /*
2  * Copyright 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.jdt;
17
18 import com.google.gwt.core.ext.TreeLogger;
19 import com.google.gwt.core.ext.UnableToCompleteException;
20
21 import org.eclipse.jdt.core.compiler.CharOperation;
22 import org.eclipse.jdt.internal.compiler.ClassFile;
23 import org.eclipse.jdt.internal.compiler.CompilationResult;
24 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
25
26 /**
27  * A facade around the JDT compiler to manage on-demand Java source to bytecode
28  * compilation, caching compiled bytecode where possible.
29  */

30 public class ByteCodeCompiler extends AbstractCompiler {
31
32   private final CacheManager cacheManager;
33
34   /**
35    * Creates a bytecode compiler for use not in hosted mode. All bytecode will
36    * be thrown away after reload.
37    *
38    * @param sourceOracle used to find the source
39    */

40   public ByteCodeCompiler(SourceOracle sourceOracle) {
41     super(sourceOracle, true);
42     this.cacheManager = new CacheManager();
43   }
44
45   /**
46    * Creates a byte code compiler given the supplied sourceOracle (to find the
47    * source) and the supplied cacheManager (to keep the bytecode and other
48    * info). If the cacheManager has a cacheDir, it will keep bytecode across
49    * reload, and load them from the cacheDir on startup. Otherwise, each reload
50    * will clear the cache. In hosted mode, the cacheManager used to create this
51    * object should be the same one used to create the typeOracleBuilder.
52    *
53    * @param sourceOracle used to find the source
54    * @param cacheManager used to keep the cached information
55    */

56   public ByteCodeCompiler(SourceOracle sourceOracle, CacheManager cacheManager) {
57     super(sourceOracle, true);
58     this.cacheManager = cacheManager;
59   }
60
61   /**
62    * Get the bytecode for the specified type.
63    *
64    * @param binaryTypeName the binary type name to look up or compile
65    */

66   public byte[] getClassBytes(TreeLogger logger, String JavaDoc binaryTypeName)
67       throws UnableToCompleteException {
68
69     // We use a thread logger proxy because we can't wind the logger through
70
// JDT directly.
71
//
72
String JavaDoc msg = "Getting bytecode for '" + binaryTypeName + "'";
73     logger = logger.branch(TreeLogger.SPAM, msg, null);
74     setLogger(logger);
75
76     // Check the bytecode cache in case we've already compiled it.
77
//
78
ByteCode byteCode = doGetByteCodeFromCache(logger, binaryTypeName);
79     if (byteCode != null) {
80       // We have it already.
81
//
82
return byteCode.getBytes();
83     }
84
85     // Need to compile it. It could be the case that we have tried before and
86
// failed, but on the off chance that it's been fixed since then, we adopt
87
// a policy of always trying to recompile if we don't have it cached.
88
//
89
ICompilationUnit start = getCompilationUnitForType(logger, binaryTypeName);
90     compile(logger, new ICompilationUnit[] {start});
91
92     // Check the cache again. If it's there now, we succeeded.
93
// If it isn't there now, we've already logged the error.
94
//
95
byteCode = doGetByteCodeFromCache(logger, binaryTypeName);
96     if (byteCode != null) {
97       return byteCode.getBytes();
98     } else {
99       throw new UnableToCompleteException();
100     }
101   }
102
103   /**
104    * Prevents the compile process from ever trying to compile these types from
105    * source. This is used for special types that would not compile correctly
106    * from source.
107    *
108    * @param binaryTypeName the binary name of the specified type
109    */

110   public void putClassBytes(TreeLogger logger, String JavaDoc binaryTypeName,
111       byte[] bytes, String JavaDoc location) {
112
113     // We must remember the package name independently in case this is a type
114
// the host doesn't actually know about.
115
//
116
String JavaDoc pkgName = "";
117     int lastDot = binaryTypeName.lastIndexOf('.');
118     if (lastDot != -1) {
119       pkgName = binaryTypeName.substring(0, lastDot);
120     }
121     rememberPackage(pkgName);
122
123     // Cache the bytes.
124
//
125
ByteCode byteCode = new ByteCode(binaryTypeName, bytes, location, true);
126     cacheManager.acceptIntoCache(logger, binaryTypeName, byteCode);
127   }
128
129   /**
130    * This method removes the bytecode which is no longer current, or if the
131    * cacheManager does not have a cacheDir, all the bytecode.
132    *
133    * @param logger used to describe the results to the user
134    */

135   public void removeStaleByteCode(TreeLogger logger) {
136     cacheManager.removeStaleByteCode(logger, this);
137   }
138
139   protected void doAcceptResult(CompilationResult result) {
140     // Take all compiled class files and put them in the byte cache.
141
//
142
TreeLogger logger = getLogger();
143     ClassFile[] classFiles = result.getClassFiles();
144     for (int i = 0; i < classFiles.length; i++) {
145       ClassFile classFile = classFiles[i];
146       char[][] compoundName = classFile.getCompoundName();
147       char[] classNameChars = CharOperation.concatWith(compoundName, '.');
148       String JavaDoc className = String.valueOf(classNameChars);
149       byte bytes[] = classFile.getBytes();
150       String JavaDoc loc = String.valueOf(result.compilationUnit.getFileName());
151       boolean isTransient = true;
152       if (result.compilationUnit instanceof ICompilationUnitAdapter) {
153         ICompilationUnitAdapter unit = (ICompilationUnitAdapter) result.compilationUnit;
154         isTransient = unit.getCompilationUnitProvider().isTransient();
155       }
156       ByteCode byteCode = new ByteCode(className, bytes, loc, isTransient);
157       if (cacheManager.acceptIntoCache(logger, className, byteCode)) {
158         logger.log(TreeLogger.SPAM, "Successfully compiled and cached '"
159             + className + "'", null);
160       }
161     }
162   }
163
164   /**
165    * Checks the cache for bytecode for the specified binary type name. Silently
166    * removes and pretends it didn't see any bytecode that is out-of-date with
167    * respect to the compilation unit that provides it.
168    */

169   protected ByteCode doGetByteCodeFromCache(TreeLogger logger,
170       String JavaDoc binaryTypeName) {
171     return cacheManager.getByteCode(logger, binaryTypeName);
172   }
173 }
174
Popular Tags