1
17 package org.apache.jasper.compiler;
18
19 import java.io.BufferedOutputStream;
20 import java.io.BufferedReader;
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.io.Reader;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.Map;
35 import java.util.StringTokenizer;
36
37 import org.apache.jasper.JasperException;
38 import org.apache.juli.logging.Log;
39 import org.apache.juli.logging.LogFactory;
40 import org.eclipse.jdt.core.compiler.IProblem;
41 import org.eclipse.jdt.internal.compiler.ClassFile;
42 import org.eclipse.jdt.internal.compiler.CompilationResult;
43 import org.eclipse.jdt.internal.compiler.Compiler;
44 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
45 import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
46 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
47 import org.eclipse.jdt.internal.compiler.IProblemFactory;
48 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
49 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
50 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
51 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
52 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
53 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
54
55
64 public class JDTCompiler extends org.apache.jasper.compiler.Compiler {
65
66 private final Log log = LogFactory.getLog(JDTCompiler.class);
67
68
71 @Override
72 protected void generateClass(Map<String,SmapStratum> smaps)
73 throws FileNotFoundException, JasperException, Exception {
74
75 long t1 = 0;
76 if (log.isDebugEnabled()) {
77 t1 = System.currentTimeMillis();
78 }
79
80 final String sourceFile = ctxt.getServletJavaFileName();
81 final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
82 String packageName = ctxt.getServletPackageName();
83 final String targetClassName =
84 ((packageName.length() != 0) ? (packageName + ".") : "")
85 + ctxt.getServletClassName();
86 final ClassLoader classLoader = ctxt.getJspLoader();
87 String[] fileNames = new String[] {sourceFile};
88 String[] classNames = new String[] {targetClassName};
89 final List<JavacErrorDetail> problemList = new ArrayList<>();
90
91 class CompilationUnit implements ICompilationUnit {
92
93 private final String className;
94 private final String sourceFile;
95
96 CompilationUnit(String sourceFile, String className) {
97 this.className = className;
98 this.sourceFile = sourceFile;
99 }
100
101 @Override
102 public char[] getFileName() {
103 return sourceFile.toCharArray();
104 }
105
106 @Override
107 public char[] getContents() {
108 char[] result = null;
109 try (FileInputStream is = new FileInputStream(sourceFile);
110 InputStreamReader isr = new InputStreamReader(
111 is, ctxt.getOptions().getJavaEncoding());
112 Reader reader = new BufferedReader(isr)) {
113 char[] chars = new char[8192];
114 StringBuilder buf = new StringBuilder();
115 int count;
116 while ((count = reader.read(chars, 0,
117 chars.length)) > 0) {
118 buf.append(chars, 0, count);
119 }
120 result = new char[buf.length()];
121 buf.getChars(0, result.length, result, 0);
122 } catch (IOException e) {
123 log.error(Localizer.getMessage("jsp.error.compilation.source", sourceFile), e);
124 }
125 return result;
126 }
127
128 @Override
129 public char[] getMainTypeName() {
130 int dot = className.lastIndexOf('.');
131 if (dot > 0) {
132 return className.substring(dot + 1).toCharArray();
133 }
134 return className.toCharArray();
135 }
136
137 @Override
138 public char[][] getPackageName() {
139 StringTokenizer izer =
140 new StringTokenizer(className, ".");
141 char[][] result = new char[izer.countTokens()-1][];
142 for (int i = 0; i < result.length; i++) {
143 String tok = izer.nextToken();
144 result[i] = tok.toCharArray();
145 }
146 return result;
147 }
148
149 @Override
150 public boolean ignoreOptionalProblems() {
151 return false;
152 }
153 }
154
155 final INameEnvironment env = new INameEnvironment() {
156
157 @Override
158 public NameEnvironmentAnswer
159 findType(char[][] compoundTypeName) {
160 StringBuilder result = new StringBuilder();
161 for (int i = 0; i < compoundTypeName.length; i++) {
162 if(i > 0)
163 result.append('.');
164 result.append(compoundTypeName[i]);
165 }
166 return findType(result.toString());
167 }
168
169 @Override
170 public NameEnvironmentAnswer
171 findType(char[] typeName,
172 char[][] packageName) {
173 StringBuilder result = new StringBuilder();
174 int i=0;
175 for (; i < packageName.length; i++) {
176 if(i > 0)
177 result.append('.');
178 result.append(packageName[i]);
179 }
180 if(i > 0)
181 result.append('.');
182 result.append(typeName);
183 return findType(result.toString());
184 }
185
186 private NameEnvironmentAnswer findType(String className) {
187
188 if (className.equals(targetClassName)) {
189 ICompilationUnit compilationUnit =
190 new CompilationUnit(sourceFile, className);
191 return
192 new NameEnvironmentAnswer(compilationUnit, null);
193 }
194
195 String resourceName =
196 className.replace('.', '/') + ".class";
197
198 try (InputStream is = classLoader.getResourceAsStream(resourceName)) {
199 if (is != null) {
200 byte[] classBytes;
201 byte[] buf = new byte[8192];
202 ByteArrayOutputStream baos =
203 new ByteArrayOutputStream(buf.length);
204 int count;
205 while ((count = is.read(buf, 0, buf.length)) > 0) {
206 baos.write(buf, 0, count);
207 }
208 baos.flush();
209 classBytes = baos.toByteArray();
210 char[] fileName = className.toCharArray();
211 ClassFileReader classFileReader =
212 new ClassFileReader(classBytes, fileName,
213 true);
214 return
215 new NameEnvironmentAnswer(classFileReader, null);
216 }
217 } catch (IOException exc) {
218 log.error(Localizer.getMessage("jsp.error.compilation.dependent", className), exc);
219 } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
220 log.error(Localizer.getMessage("jsp.error.compilation.dependent", className), exc);
221 }
222 return null;
223 }
224
225 private boolean isPackage(String result) {
226 if (result.equals(targetClassName)) {
227 return false;
228 }
229 String resourceName = result.replace('.', '/') + ".class";
230 try (InputStream is =
231 classLoader.getResourceAsStream(resourceName)) {
232 return is == null;
233 } catch (IOException e) {
234
235 return false;
236 }
237 }
238
239 @Override
240 public boolean isPackage(char[][] parentPackageName,
241 char[] packageName) {
242 StringBuilder result = new StringBuilder();
243 int i=0;
244 if (parentPackageName != null) {
245 for (; i < parentPackageName.length; i++) {
246 if(i > 0)
247 result.append('.');
248 result.append(parentPackageName[i]);
249 }
250 }
251
252 if (Character.isUpperCase(packageName[0])) {
253 if (!isPackage(result.toString())) {
254 return false;
255 }
256 }
257 if(i > 0)
258 result.append('.');
259 result.append(packageName);
260
261 return isPackage(result.toString());
262 }
263
264 @Override
265 public void cleanup() {
266 }
267
268 };
269
270 final IErrorHandlingPolicy policy =
271 DefaultErrorHandlingPolicies.proceedWithAllProblems();
272
273 final Map<String,String> settings = new HashMap<>();
274 settings.put(CompilerOptions.OPTION_LineNumberAttribute,
275 CompilerOptions.GENERATE);
276 settings.put(CompilerOptions.OPTION_SourceFileAttribute,
277 CompilerOptions.GENERATE);
278 settings.put(CompilerOptions.OPTION_ReportDeprecation,
279 CompilerOptions.IGNORE);
280 if (ctxt.getOptions().getJavaEncoding() != null) {
281 settings.put(CompilerOptions.OPTION_Encoding,
282 ctxt.getOptions().getJavaEncoding());
283 }
284 if (ctxt.getOptions().getClassDebugInfo()) {
285 settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
286 CompilerOptions.GENERATE);
287 }
288
289
290 if(ctxt.getOptions().getCompilerSourceVM() != null) {
291 String opt = ctxt.getOptions().getCompilerSourceVM();
292 if(opt.equals("1.1")) {
293 settings.put(CompilerOptions.OPTION_Source,
294 CompilerOptions.VERSION_1_1);
295 } else if(opt.equals("1.2")) {
296 settings.put(CompilerOptions.OPTION_Source,
297 CompilerOptions.VERSION_1_2);
298 } else if(opt.equals("1.3")) {
299 settings.put(CompilerOptions.OPTION_Source,
300 CompilerOptions.VERSION_1_3);
301 } else if(opt.equals("1.4")) {
302 settings.put(CompilerOptions.OPTION_Source,
303 CompilerOptions.VERSION_1_4);
304 } else if(opt.equals("1.5")) {
305 settings.put(CompilerOptions.OPTION_Source,
306 CompilerOptions.VERSION_1_5);
307 } else if(opt.equals("1.6")) {
308 settings.put(CompilerOptions.OPTION_Source,
309 CompilerOptions.VERSION_1_6);
310 } else if(opt.equals("1.7")) {
311 settings.put(CompilerOptions.OPTION_Source,
312 CompilerOptions.VERSION_1_7);
313 } else if(opt.equals("1.8")) {
314 settings.put(CompilerOptions.OPTION_Source,
315 CompilerOptions.VERSION_1_8);
316
317
318 } else if(opt.equals("9") || opt.equals("1.9")) {
319 settings.put(CompilerOptions.OPTION_Source,
320 CompilerOptions.VERSION_9);
321 } else if(opt.equals("10")) {
322 settings.put(CompilerOptions.OPTION_Source,
323 CompilerOptions.VERSION_10);
324 } else if(opt.equals("11")) {
325 settings.put(CompilerOptions.OPTION_Source,
326 CompilerOptions.VERSION_11);
327 } else if(opt.equals("12")) {
328 settings.put(CompilerOptions.OPTION_Source,
329 CompilerOptions.VERSION_12);
330 } else if(opt.equals("13")) {
331
332
333
334 settings.put(CompilerOptions.OPTION_Source, "13");
335 } else {
336 log.warn(Localizer.getMessage("jsp.warning.unknown.sourceVM", opt));
337 settings.put(CompilerOptions.OPTION_Source,
338 CompilerOptions.VERSION_1_8);
339 }
340 } else {
341
342 settings.put(CompilerOptions.OPTION_Source,
343 CompilerOptions.VERSION_1_8);
344 }
345
346
347 if(ctxt.getOptions().getCompilerTargetVM() != null) {
348 String opt = ctxt.getOptions().getCompilerTargetVM();
349 if(opt.equals("1.1")) {
350 settings.put(CompilerOptions.OPTION_TargetPlatform,
351 CompilerOptions.VERSION_1_1);
352 } else if(opt.equals("1.2")) {
353 settings.put(CompilerOptions.OPTION_TargetPlatform,
354 CompilerOptions.VERSION_1_2);
355 } else if(opt.equals("1.3")) {
356 settings.put(CompilerOptions.OPTION_TargetPlatform,
357 CompilerOptions.VERSION_1_3);
358 } else if(opt.equals("1.4")) {
359 settings.put(CompilerOptions.OPTION_TargetPlatform,
360 CompilerOptions.VERSION_1_4);
361 } else if(opt.equals("1.5")) {
362 settings.put(CompilerOptions.OPTION_TargetPlatform,
363 CompilerOptions.VERSION_1_5);
364 settings.put(CompilerOptions.OPTION_Compliance,
365 CompilerOptions.VERSION_1_5);
366 } else if(opt.equals("1.6")) {
367 settings.put(CompilerOptions.OPTION_TargetPlatform,
368 CompilerOptions.VERSION_1_6);
369 settings.put(CompilerOptions.OPTION_Compliance,
370 CompilerOptions.VERSION_1_6);
371 } else if(opt.equals("1.7")) {
372 settings.put(CompilerOptions.OPTION_TargetPlatform,
373 CompilerOptions.VERSION_1_7);
374 settings.put(CompilerOptions.OPTION_Compliance,
375 CompilerOptions.VERSION_1_7);
376 } else if(opt.equals("1.8")) {
377 settings.put(CompilerOptions.OPTION_TargetPlatform,
378 CompilerOptions.VERSION_1_8);
379 settings.put(CompilerOptions.OPTION_Compliance,
380 CompilerOptions.VERSION_1_8);
381
382
383 } else if(opt.equals("9") || opt.equals("1.9")) {
384 settings.put(CompilerOptions.OPTION_TargetPlatform,
385 CompilerOptions.VERSION_9);
386 settings.put(CompilerOptions.OPTION_Compliance,
387 CompilerOptions.VERSION_9);
388 } else if(opt.equals("10")) {
389 settings.put(CompilerOptions.OPTION_TargetPlatform,
390 CompilerOptions.VERSION_10);
391 settings.put(CompilerOptions.OPTION_Compliance,
392 CompilerOptions.VERSION_10);
393 } else if(opt.equals("11")) {
394 settings.put(CompilerOptions.OPTION_TargetPlatform,
395 CompilerOptions.VERSION_11);
396 settings.put(CompilerOptions.OPTION_Compliance,
397 CompilerOptions.VERSION_11);
398 } else if(opt.equals("12")) {
399 settings.put(CompilerOptions.OPTION_TargetPlatform,
400 CompilerOptions.VERSION_12);
401 settings.put(CompilerOptions.OPTION_Compliance,
402 CompilerOptions.VERSION_12);
403 } else if(opt.equals("13")) {
404
405
406
407 settings.put(CompilerOptions.OPTION_TargetPlatform, "13");
408 settings.put(CompilerOptions.OPTION_Compliance, "13");
409 } else {
410 log.warn(Localizer.getMessage("jsp.warning.unknown.targetVM", opt));
411 settings.put(CompilerOptions.OPTION_TargetPlatform,
412 CompilerOptions.VERSION_1_8);
413 }
414 } else {
415
416 settings.put(CompilerOptions.OPTION_TargetPlatform,
417 CompilerOptions.VERSION_1_8);
418 settings.put(CompilerOptions.OPTION_Compliance,
419 CompilerOptions.VERSION_1_8);
420 }
421
422 final IProblemFactory problemFactory =
423 new DefaultProblemFactory(Locale.getDefault());
424
425 final ICompilerRequestor requestor = new ICompilerRequestor() {
426 @Override
427 public void acceptResult(CompilationResult result) {
428 try {
429 if (result.hasProblems()) {
430 IProblem[] problems = result.getProblems();
431 for (int i = 0; i < problems.length; i++) {
432 IProblem problem = problems[i];
433 if (problem.isError()) {
434 String name =
435 new String(problems[i].getOriginatingFileName());
436 try {
437 problemList.add(ErrorDispatcher.createJavacError
438 (name, pageNodes, new StringBuilder(problem.getMessage()),
439 problem.getSourceLineNumber(), ctxt));
440 } catch (JasperException e) {
441 log.error(Localizer.getMessage("jsp.error.compilation.jdtProblemError"), e);
442 }
443 }
444 }
445 }
446 if (problemList.isEmpty()) {
447 ClassFile[] classFiles = result.getClassFiles();
448 for (int i = 0; i < classFiles.length; i++) {
449 ClassFile classFile = classFiles[i];
450 char[][] compoundName =
451 classFile.getCompoundName();
452 StringBuilder classFileName = new StringBuilder(outputDir).append('/');
453 for (int j = 0;
454 j < compoundName.length; j++) {
455 if(j > 0)
456 classFileName.append('/');
457 classFileName.append(compoundName[j]);
458 }
459 byte[] bytes = classFile.getBytes();
460 classFileName.append(".class");
461 try (FileOutputStream fout = new FileOutputStream(
462 classFileName.toString());
463 BufferedOutputStream bos = new BufferedOutputStream(fout)) {
464 bos.write(bytes);
465 }
466 }
467 }
468 } catch (IOException exc) {
469 log.error(Localizer.getMessage("jsp.error.compilation.jdt"), exc);
470 }
471 }
472 };
473
474 ICompilationUnit[] compilationUnits =
475 new ICompilationUnit[classNames.length];
476 for (int i = 0; i < compilationUnits.length; i++) {
477 String className = classNames[i];
478 compilationUnits[i] = new CompilationUnit(fileNames[i], className);
479 }
480 CompilerOptions cOptions = new CompilerOptions(settings);
481
482
483
484
485 String requestedSource = ctxt.getOptions().getCompilerSourceVM();
486 if (requestedSource != null) {
487 String actualSource = CompilerOptions.versionFromJdkLevel(cOptions.sourceLevel);
488 if (!requestedSource.equals(actualSource)) {
489 log.warn(Localizer.getMessage("jsp.warning.unsupported.sourceVM", requestedSource, actualSource));
490 }
491 }
492 String requestedTarget = ctxt.getOptions().getCompilerTargetVM();
493 if (requestedTarget != null) {
494 String actualTarget = CompilerOptions.versionFromJdkLevel(cOptions.targetJDK);
495 if (!requestedTarget.equals(actualTarget)) {
496 log.warn(Localizer.getMessage("jsp.warning.unsupported.targetVM", requestedTarget, actualTarget));
497 }
498 }
499
500 cOptions.parseLiteralExpressionsAsConstants = true;
501 Compiler compiler = new Compiler(env,
502 policy,
503 cOptions,
504 requestor,
505 problemFactory);
506 compiler.compile(compilationUnits);
507
508 if (!ctxt.keepGenerated()) {
509 File javaFile = new File(ctxt.getServletJavaFileName());
510 if (!javaFile.delete()) {
511 throw new JasperException(Localizer.getMessage(
512 "jsp.warning.compiler.javafile.delete.fail", javaFile));
513 }
514 }
515
516 if (!problemList.isEmpty()) {
517 JavacErrorDetail[] jeds =
518 problemList.toArray(new JavacErrorDetail[0]);
519 errDispatcher.javacError(jeds);
520 }
521
522 if( log.isDebugEnabled() ) {
523 long t2=System.currentTimeMillis();
524 log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
525 + (t2-t1) + "ms");
526 }
527
528 if (ctxt.isPrototypeMode()) {
529 return;
530 }
531
532
533 if (! options.isSmapSuppressed()) {
534 SmapUtil.installSmap(smaps);
535 }
536 }
537 }
538