PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/org/rythmengine/internal/compiler/TemplateCompiler.java

http://github.com/greenlaw110/Rythm
Java | 346 lines | 244 code | 40 blank | 62 comment | 51 complexity | 620b431fcaf962709712521b3029ba50 MD5 | raw file
  1. /**
  2. * Copyright (C) 2013-2016 The Rythm Engine project
  3. * for LICENSE and other details see:
  4. * https://github.com/rythmengine/rythmengine
  5. */
  6. package org.rythmengine.internal.compiler;
  7. /*-
  8. * #%L
  9. * Rythm Template Engine
  10. * %%
  11. * Copyright (C) 2017 - 2021 OSGL (Open Source General Library)
  12. * %%
  13. * Licensed under the Apache License, Version 2.0 (the "License");
  14. * you may not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an "AS IS" BASIS,
  21. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. * #L%
  25. */
  26. import org.rythmengine.RythmEngine;
  27. import org.rythmengine.exception.CompileException;
  28. import org.rythmengine.logger.ILogger;
  29. import org.rythmengine.logger.Logger;
  30. import org.eclipse.jdt.core.compiler.IProblem;
  31. import org.eclipse.jdt.internal.compiler.*;
  32. import org.eclipse.jdt.internal.compiler.Compiler;
  33. import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
  34. import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
  35. import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
  36. import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
  37. import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
  38. import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
  39. import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
  40. import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
  41. import java.util.*;
  42. /**
  43. * Created by IntelliJ IDEA.
  44. * User: luog
  45. * Date: 18/01/12
  46. * Time: 7:10 PM
  47. * To change this template use File | Settings | File Templates.
  48. */
  49. public class TemplateCompiler {
  50. private final static ILogger logger = Logger.get(TemplateCompiler.class);
  51. private RythmEngine engine() {
  52. return classCache.engine;
  53. }
  54. Map<String, Boolean> packagesCache = new HashMap<String, Boolean>();
  55. // -- util methods
  56. private String getTemplateByClassName(String className) {
  57. TemplateClass tc = engine().classes().getByClassName(className);
  58. return null == tc ? null : tc.getKey().toString();
  59. }
  60. // -- the following code comes from PlayFramework 1.2
  61. TemplateClassManager classCache;
  62. Map<String, String> settings;
  63. /**
  64. * Try to guess the magic configuration options
  65. */
  66. public TemplateCompiler(TemplateClassManager classCache) {
  67. this.classCache = classCache;
  68. this.settings = new HashMap<String, String>();
  69. this.settings.put(CompilerOptions.OPTION_ReportMissingSerialVersion, CompilerOptions.IGNORE);
  70. this.settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE);
  71. this.settings.put(CompilerOptions.OPTION_ReportUnusedImport, CompilerOptions.IGNORE);
  72. this.settings.put(CompilerOptions.OPTION_Encoding, "UTF-8");
  73. this.settings.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE);
  74. this.settings.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE);
  75. this.settings.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE);
  76. String javaVersion = CompilerOptions.VERSION_1_6;
  77. String provisionedJavaVersion = System.getProperty("java.version");
  78. if (provisionedJavaVersion.startsWith("1.7")) {
  79. javaVersion = CompilerOptions.VERSION_1_7;
  80. } else if (provisionedJavaVersion.startsWith("1.8")) {
  81. javaVersion = CompilerOptions.VERSION_1_8;
  82. }
  83. this.settings.put(CompilerOptions.OPTION_Source, javaVersion);
  84. this.settings.put(CompilerOptions.OPTION_TargetPlatform, javaVersion);
  85. this.settings.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.PRESERVE);
  86. this.settings.put(CompilerOptions.OPTION_Compliance, javaVersion);
  87. }
  88. /**
  89. * Something to compile
  90. */
  91. final class CompilationUnit implements ICompilationUnit {
  92. final private String clazzName;
  93. final private String fileName;
  94. final private char[] typeName;
  95. final private char[][] packageName;
  96. CompilationUnit(String pClazzName) {
  97. clazzName = pClazzName;
  98. if (pClazzName.contains("$")) {
  99. pClazzName = pClazzName.substring(0, pClazzName.indexOf("$"));
  100. }
  101. fileName = pClazzName.replace('.', '/') + ".java";
  102. int dot = pClazzName.lastIndexOf('.');
  103. if (dot > 0) {
  104. typeName = pClazzName.substring(dot + 1).toCharArray();
  105. } else {
  106. typeName = pClazzName.toCharArray();
  107. }
  108. StringTokenizer st = new StringTokenizer(pClazzName, ".");
  109. packageName = new char[st.countTokens() - 1][];
  110. for (int i = 0; i < packageName.length; i++) {
  111. packageName[i] = st.nextToken().toCharArray();
  112. }
  113. }
  114. @Override
  115. public boolean ignoreOptionalProblems() {
  116. return false;
  117. }
  118. public char[] getFileName() {
  119. return fileName.toCharArray();
  120. }
  121. public char[] getContents() {
  122. if (null == classCache) {
  123. throw new NullPointerException("classCache is null");
  124. }
  125. TemplateClass tc = classCache.getByClassName(clazzName);
  126. if (null == tc) {
  127. throw new NullPointerException("Error get java source content for " + clazzName + ": template class is null");
  128. }
  129. if (null == tc.javaSource) {
  130. throw new NullPointerException("Error get java source content for " + clazzName + ": java source is null");
  131. }
  132. return tc.javaSource.toCharArray();
  133. //return classCache.getByClassName(clazzName).javaSource.toCharArray();
  134. }
  135. public char[] getMainTypeName() {
  136. return typeName;
  137. }
  138. public char[][] getPackageName() {
  139. return packageName;
  140. }
  141. }
  142. final Set<String> notFoundTypes = new HashSet<String>();
  143. /**
  144. * Please compile this className
  145. */
  146. @SuppressWarnings("deprecation")
  147. public void compile(String[] classNames) {
  148. ICompilationUnit[] compilationUnits = new CompilationUnit[classNames.length];
  149. for (int i = 0; i < classNames.length; i++) {
  150. compilationUnits[i] = new CompilationUnit(classNames[i]);
  151. }
  152. IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitOnFirstError();
  153. IProblemFactory problemFactory = new DefaultProblemFactory(Locale.ENGLISH);
  154. /**
  155. * To find types ...
  156. */
  157. INameEnvironment nameEnvironment = new INameEnvironment() {
  158. public NameEnvironmentAnswer findType(final char[][] compoundTypeName) {
  159. final StringBuffer result = new StringBuffer();
  160. for (int i = 0; i < compoundTypeName.length; i++) {
  161. if (i != 0) {
  162. result.append('.');
  163. }
  164. result.append(compoundTypeName[i]);
  165. }
  166. return findType(result.toString());
  167. }
  168. public NameEnvironmentAnswer findType(final char[] typeName, final char[][] packageName) {
  169. final StringBuffer result = new StringBuffer();
  170. for (int i = 0; i < packageName.length; i++) {
  171. result.append(packageName[i]);
  172. result.append('.');
  173. }
  174. result.append(typeName);
  175. return findType(result.toString());
  176. }
  177. private NameEnvironmentAnswer findStandType(final String name) throws ClassFormatException {
  178. if (notFoundTypes.contains(name)) {
  179. return null;
  180. }
  181. RythmEngine engine = engine();
  182. byte[] bytes = engine.classLoader().getClassDefinition(name);
  183. if (bytes != null) {
  184. ClassFileReader classFileReader = new ClassFileReader(bytes, name.toCharArray(), true);
  185. return new NameEnvironmentAnswer(classFileReader, null);
  186. }
  187. if (engine.isProdMode()) {
  188. notFoundTypes.add(name);
  189. } else if (name.matches("^(java\\.|play\\.|com\\.greenlaw110\\.).*")) {
  190. notFoundTypes.add(name);
  191. }
  192. return null;
  193. }
  194. private NameEnvironmentAnswer findType(final String name) {
  195. try {
  196. if (!name.contains(TemplateClass.CN_SUFFIX)) {
  197. return findStandType(name);
  198. }
  199. char[] fileName = name.toCharArray();
  200. TemplateClass templateClass = classCache.getByClassName(name);
  201. // TemplateClass exists
  202. if (templateClass != null) {
  203. if (templateClass.javaByteCode != null) {
  204. ClassFileReader classFileReader = new ClassFileReader(templateClass.javaByteCode, fileName, true);
  205. return new NameEnvironmentAnswer(classFileReader, null);
  206. }
  207. // Cascade compilation
  208. ICompilationUnit compilationUnit = new CompilationUnit(name);
  209. return new NameEnvironmentAnswer(compilationUnit, null);
  210. }
  211. // So it's a standard class
  212. return findStandType(name);
  213. } catch (ClassFormatException e) {
  214. // Something very very bad
  215. throw new RuntimeException(e);
  216. }
  217. }
  218. @Override
  219. public boolean isPackage(char[][] parentPackageName, char[] packageName) {
  220. // Rebuild something usable
  221. StringBuilder sb = new StringBuilder();
  222. if (parentPackageName != null) {
  223. for (char[] p : parentPackageName) {
  224. sb.append(new String(p));
  225. sb.append(".");
  226. }
  227. }
  228. sb.append(new String(packageName));
  229. String name = sb.toString();
  230. if (packagesCache.containsKey(name)) {
  231. return packagesCache.get(name).booleanValue();
  232. }
  233. // Check if thera a .java or .class for this resource
  234. if (engine().classLoader().getClassDefinition(name) != null) {
  235. packagesCache.put(name, false);
  236. return false;
  237. }
  238. if (engine().classes().getByClassName(name) != null) {
  239. packagesCache.put(name, false);
  240. return false;
  241. }
  242. packagesCache.put(name, true);
  243. return true;
  244. }
  245. public void cleanup() {
  246. }
  247. };
  248. /**
  249. * Compilation result
  250. */
  251. ICompilerRequestor compilerRequestor = new ICompilerRequestor() {
  252. public void acceptResult(CompilationResult result) {
  253. // If error
  254. if (result.hasErrors()) {
  255. for (IProblem problem : result.getErrors()) {
  256. int line = problem.getSourceLineNumber();
  257. String message = problem.getMessage();
  258. throw CompileException.compilerException(String.valueOf(result.compilationUnit.getMainTypeName()), line, message);
  259. }
  260. }
  261. // Something has been compiled
  262. ClassFile[] clazzFiles = result.getClassFiles();
  263. for (int i = 0; i < clazzFiles.length; i++) {
  264. final ClassFile clazzFile = clazzFiles[i];
  265. final char[][] compoundName = clazzFile.getCompoundName();
  266. final StringBuffer clazzName = new StringBuffer();
  267. for (int j = 0; j < compoundName.length; j++) {
  268. if (j != 0) {
  269. clazzName.append('.');
  270. }
  271. clazzName.append(compoundName[j]);
  272. }
  273. if (logger.isTraceEnabled()) {
  274. logger.trace("Compiled %s", getTemplateByClassName(clazzName.toString()));
  275. }
  276. String cn = clazzName.toString();
  277. TemplateClass tc = classCache.getByClassName(cn);
  278. if (null == tc) {
  279. int pos = cn.indexOf("$");
  280. if (-1 != pos) {
  281. // inner class
  282. TemplateClass root = classCache.getByClassName(cn.substring(0, pos));
  283. tc = TemplateClass.createInnerClass(cn, clazzFile.getBytes(), root);
  284. tc.delayedEnhance(root);
  285. classCache.add(tc);
  286. } else {
  287. throw new RuntimeException("Cannot find class by name: " + cn);
  288. }
  289. } else {
  290. tc.compiled(clazzFile.getBytes());
  291. }
  292. }
  293. }
  294. };
  295. /**
  296. * The JDT compiler
  297. */
  298. Compiler jdtCompiler = new Compiler(nameEnvironment, policy, settings, compilerRequestor, problemFactory) {
  299. @Override
  300. protected void handleInternalException(Throwable e, CompilationUnitDeclaration ud, CompilationResult result) {
  301. }
  302. };
  303. // Go !
  304. jdtCompiler.compile(compilationUnits);
  305. }
  306. }