1   package org.codehaus.plexus.compiler.ajc;
2   
3   import javax.inject.Named;
4   
5   import java.io.File;
6   import java.io.IOException;
7   import java.net.MalformedURLException;
8   import java.net.URL;
9   import java.net.URLClassLoader;
10  import java.util.ArrayList;
11  import java.util.Arrays;
12  import java.util.HashSet;
13  import java.util.LinkedList;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Set;
17  
18  import org.aspectj.ajdt.ajc.BuildArgParser;
19  import org.aspectj.ajdt.internal.core.builder.AjBuildConfig;
20  import org.aspectj.ajdt.internal.core.builder.AjBuildManager;
21  import org.aspectj.bridge.AbortException;
22  import org.aspectj.bridge.IMessage;
23  import org.aspectj.bridge.ISourceLocation;
24  import org.aspectj.bridge.MessageHandler;
25  import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
26  import org.aspectj.tools.ajc.Main;
27  import org.codehaus.plexus.compiler.AbstractCompiler;
28  import org.codehaus.plexus.compiler.CompilerConfiguration;
29  import org.codehaus.plexus.compiler.CompilerException;
30  import org.codehaus.plexus.compiler.CompilerMessage;
31  import org.codehaus.plexus.compiler.CompilerOutputStyle;
32  import org.codehaus.plexus.compiler.CompilerResult;
33  import org.codehaus.plexus.util.DirectoryScanner;
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186 
187 
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207 
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254 
255 
256 
257 
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270 
271 
272 
273 
274 
275 
276 
277 
278 
279 
280 
281 
282 
283 
284 
285 
286 
287 
288 
289 
290 @Named("aspectj")
291 public class AspectJCompiler extends AbstractCompiler {
292 
293     
294     
295     
296 
297     public AspectJCompiler() {
298         
299         
300         super(CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, "", ".class", null);
301     }
302 
303     @Override
304     public String getCompilerId() {
305         return "aspectj";
306     }
307 
308     public CompilerResult performCompile(CompilerConfiguration config) throws CompilerException {
309         File destinationDir = new File(config.getOutputLocation());
310 
311         if (!destinationDir.exists()) {
312             destinationDir.mkdirs();
313         }
314 
315         String[] sourceFiles = getSourceFiles(config);
316 
317         if (sourceFiles.length == 0) {
318             return new CompilerResult();
319         }
320 
321         logCompiling(sourceFiles, config);
322 
323         
324         AjBuildConfig buildConfig = buildCompilerConfig(config);
325         return new CompilerResult().compilerMessages(compileInProcess(buildConfig));
326     }
327 
328     private static class AspectJMessagePrinter extends Main.MessagePrinter {
329         public AspectJMessagePrinter(boolean verbose) {
330             super(verbose);
331         }
332     }
333 
334     private AjBuildConfig buildCompilerConfig(CompilerConfiguration config) throws CompilerException {
335         BuildArgParser buildArgParser = new BuildArgParser(new AspectJMessagePrinter(config.isVerbose()));
336         AjBuildConfig buildConfig = new AjBuildConfig(buildArgParser);
337         
338         buildArgParser.populateBuildConfig(buildConfig, new String[0], true, null);
339         buildConfig.setIncrementalMode(false);
340 
341         String[] files = getSourceFiles(config);
342         if (files != null) {
343             buildConfig.setFiles(buildFileList(Arrays.asList(files)));
344         }
345 
346         String releaseVersion = config.getReleaseVersion();
347         setSourceVersion(buildConfig, releaseVersion == null ? config.getSourceVersion() : releaseVersion);
348         setTargetVersion(buildConfig, releaseVersion == null ? config.getTargetVersion() : releaseVersion);
349 
350         if (config.isDebug()) {
351             buildConfig.getOptions().produceDebugAttributes =
352                     ClassFileConstants.ATTR_SOURCE + ClassFileConstants.ATTR_LINES + ClassFileConstants.ATTR_VARS;
353         }
354 
355         Map<String, String> javaOpts = config.getCustomCompilerArgumentsAsMap();
356         if (javaOpts != null && !javaOpts.isEmpty()) {
357             
358             
359         }
360 
361         List<String> cp = new LinkedList<>(config.getClasspathEntries());
362 
363         File javaHomeDir = new File(System.getProperty("java.home"));
364         File[] jars = new File(javaHomeDir, "lib").listFiles();
365         if (jars != null) {
366             for (File jar : jars) {
367                 if (jar.getName().endsWith(".jar") || jar.getName().endsWith(".zip")) {
368                     cp.add(0, jar.getAbsolutePath());
369                 }
370             }
371         }
372         jars = new File(javaHomeDir, "../Classes").listFiles();
373         if (jars != null) {
374             for (File jar : jars) {
375                 if (jar.getName().endsWith(".jar") || jar.getName().endsWith(".zip")) {
376                     cp.add(0, jar.getAbsolutePath());
377                 }
378             }
379         }
380 
381         checkForAspectJRT(cp);
382         if (cp != null && !cp.isEmpty()) {
383             List<String> elements = new ArrayList<>(cp.size());
384             for (String path : cp) {
385                 elements.add((new File(path)).getAbsolutePath());
386             }
387 
388             buildConfig.setClasspath(elements);
389         }
390 
391         String outputLocation = config.getOutputLocation();
392         if (outputLocation != null) {
393             File outDir = new File(outputLocation);
394             if (!outDir.exists()) {
395                 outDir.mkdirs();
396             }
397 
398             buildConfig.setOutputDir(outDir);
399         }
400 
401         if (config instanceof AspectJCompilerConfiguration) {
402             AspectJCompilerConfiguration ajCfg = (AspectJCompilerConfiguration) config;
403 
404             Map<String, File> sourcePathResources = ajCfg.getSourcePathResources();
405             if (sourcePathResources != null && !sourcePathResources.isEmpty()) {
406                 buildConfig.setSourcePathResources(sourcePathResources);
407             }
408 
409             Map<String, String> ajOptions = ajCfg.getAJOptions();
410             if (ajOptions != null && !ajOptions.isEmpty()) {
411                 
412                 
413             }
414 
415             List<File> aspectPath = buildFileList(ajCfg.getAspectPath());
416             if (aspectPath != null && !aspectPath.isEmpty()) {
417                 buildConfig.setAspectpath(buildFileList(ajCfg.getAspectPath()));
418             }
419 
420             List<File> inJars = buildFileList(ajCfg.getInJars());
421             if (inJars != null && !inJars.isEmpty()) {
422                 buildConfig.setInJars(buildFileList(ajCfg.getInJars()));
423             }
424 
425             List<File> inPaths = buildFileList(ajCfg.getInPath());
426             if (inPaths != null && !inPaths.isEmpty()) {
427                 buildConfig.setInPath(buildFileList(ajCfg.getInPath()));
428             }
429 
430             String outJar = ajCfg.getOutputJar();
431             if (outJar != null) {
432                 buildConfig.setOutputJar(new File(ajCfg.getOutputJar()));
433             }
434         }
435 
436         return buildConfig;
437     }
438 
439     private List<CompilerMessage> compileInProcess(AjBuildConfig buildConfig) throws CompilerException {
440 
441         MessageHandler messageHandler = new MessageHandler();
442 
443         AjBuildManager manager = new AjBuildManager(messageHandler);
444 
445         try {
446             manager.batchBuild(buildConfig, messageHandler);
447         } catch (AbortException | IOException e) {
448             throw new CompilerException("Unknown error while compiling", e);
449         }
450 
451         
452         
453         
454         
455         
456         
457         
458         
459 
460         boolean errors = messageHandler.hasAnyMessage(IMessage.ERROR, true);
461 
462         List<CompilerMessage> messages = new ArrayList<>();
463         if (errors) {
464             IMessage[] errorMessages = messageHandler.getMessages(IMessage.ERROR, true);
465 
466             for (IMessage m : errorMessages) {
467                 ISourceLocation sourceLocation = m.getSourceLocation();
468                 CompilerMessage error;
469 
470                 if (sourceLocation == null) {
471                     error = new CompilerMessage(m.getMessage(), true);
472                 } else {
473                     error = new CompilerMessage(
474                             sourceLocation.getSourceFile().getPath(),
475                             true,
476                             sourceLocation.getLine(),
477                             sourceLocation.getColumn(),
478                             sourceLocation.getEndLine(),
479                             sourceLocation.getColumn(),
480                             m.getMessage());
481                 }
482                 messages.add(error);
483             }
484         }
485 
486         return messages;
487     }
488 
489     private void checkForAspectJRT(List<String> cp) {
490         if (cp == null || cp.isEmpty()) {
491             throw new IllegalStateException("AspectJ Runtime not found in supplied classpath");
492         } else {
493             try {
494                 URL[] urls = new URL[cp.size()];
495                 for (int i = 0; i < urls.length; i++) {
496                     urls[i] = (new File(cp.get(i))).toURL();
497                 }
498 
499                 URLClassLoader cloader = new URLClassLoader(urls);
500 
501                 cloader.loadClass("org.aspectj.lang.JoinPoint");
502             } catch (MalformedURLException e) {
503                 throw new IllegalArgumentException("Invalid classpath entry");
504             } catch (ClassNotFoundException e) {
505                 throw new IllegalStateException("AspectJ Runtime not found in supplied classpath");
506             }
507         }
508     }
509 
510     private List<File> buildFileList(List<String> locations) {
511         List<File> fileList = new LinkedList<>();
512         for (String location : locations) {
513             fileList.add(new File(location));
514         }
515 
516         return fileList;
517     }
518 
519     
520 
521 
522 
523 
524 
525     private void setSourceVersion(AjBuildConfig buildConfig, String sourceVersion) throws CompilerException {
526         buildConfig.getOptions().sourceLevel = versionStringToMajorMinor(sourceVersion);
527     }
528 
529     
530 
531 
532 
533 
534 
535     private void setTargetVersion(AjBuildConfig buildConfig, String targetVersion) throws CompilerException {
536         buildConfig.getOptions().targetJDK = versionStringToMajorMinor(targetVersion);
537     }
538 
539     private static long versionStringToMajorMinor(String version) throws CompilerException {
540         if (version == null) {
541             version = "";
542         }
543         
544         
545         
546 
547         version = version.trim()
548                 
549                 .replaceFirst("^1[.]", "")
550                 
551                 .replaceFirst("[.]0$", "");
552 
553         switch (version) {
554                 
555                 
556             case "":
557                 return ClassFileConstants.JDK1_6;
558             case "1":
559                 return ClassFileConstants.JDK1_1;
560             case "2":
561                 return ClassFileConstants.JDK1_2;
562             case "3":
563                 return ClassFileConstants.JDK1_3;
564             case "4":
565                 return ClassFileConstants.JDK1_4;
566             case "5":
567                 return ClassFileConstants.JDK1_5;
568             case "6":
569                 return ClassFileConstants.JDK1_6;
570             case "7":
571                 return ClassFileConstants.JDK1_7;
572             case "8":
573                 return ClassFileConstants.JDK1_8;
574             case "9":
575                 return ClassFileConstants.JDK9;
576             case "10":
577                 return ClassFileConstants.JDK10;
578             case "11":
579                 return ClassFileConstants.JDK11;
580             case "12":
581                 return ClassFileConstants.JDK12;
582             case "13":
583                 return ClassFileConstants.JDK13;
584             case "14":
585                 return ClassFileConstants.JDK14;
586             case "15":
587                 return ClassFileConstants.JDK15;
588             case "16":
589                 return ClassFileConstants.JDK16;
590         }
591         throw new CompilerException("Unknown Java source/target version number: " + version);
592     }
593 
594     
595 
596 
597     public String[] createCommandLine(CompilerConfiguration config) throws CompilerException {
598         return null;
599     }
600 
601     protected static String[] getSourceFiles(CompilerConfiguration config) {
602         Set<String> sources = new HashSet<>();
603 
604         Set<File> sourceFiles = config.getSourceFiles();
605 
606         if (sourceFiles != null && !sourceFiles.isEmpty()) {
607             for (File sourceFile : sourceFiles) {
608                 if (sourceFile.getName().endsWith(".java")
609                         || sourceFile.getName().endsWith(".aj")) {
610                     sources.add(sourceFile.getAbsolutePath());
611                 }
612             }
613         } else {
614             for (String sourceLocation : config.getSourceLocations()) {
615                 sources.addAll(getSourceFilesForSourceRoot(config, sourceLocation));
616             }
617         }
618 
619         String[] result;
620 
621         if (sources.isEmpty()) {
622             result = new String[0];
623         } else {
624             result = sources.toArray(new String[sources.size()]);
625         }
626 
627         return result;
628     }
629 
630     protected static Set<String> getSourceFilesForSourceRoot(CompilerConfiguration config, String sourceLocation) {
631         DirectoryScanner scanner = new DirectoryScanner();
632 
633         scanner.setBasedir(sourceLocation);
634 
635         Set<String> includes = config.getIncludes();
636 
637         if (includes != null && !includes.isEmpty()) {
638             String[] inclStrs = includes.toArray(new String[includes.size()]);
639             scanner.setIncludes(inclStrs);
640         } else {
641             scanner.setIncludes(new String[] {"**/*.java", "**/*.aj"});
642         }
643 
644         Set<String> excludes = config.getExcludes();
645 
646         if (excludes != null && !excludes.isEmpty()) {
647             String[] exclStrs = excludes.toArray(new String[excludes.size()]);
648             scanner.setExcludes(exclStrs);
649         }
650 
651         scanner.scan();
652 
653         String[] sourceDirectorySources = scanner.getIncludedFiles();
654 
655         Set<String> sources = new HashSet<>();
656 
657         for (String sourceDirectorySource : sourceDirectorySources) {
658             File f = new File(sourceLocation, sourceDirectorySource);
659 
660             sources.add(f.getPath());
661         }
662 
663         return sources;
664     }
665 }