1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.jspc.plugin;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileFilter;
24 import java.io.FileReader;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.io.PrintWriter;
28 import java.net.URI;
29 import java.net.URL;
30 import java.net.URLClassLoader;
31 import java.util.ArrayList;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.regex.Pattern;
36
37 import org.apache.jasper.JspC;
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.plugin.AbstractMojo;
40 import org.apache.maven.plugin.MojoExecutionException;
41 import org.apache.maven.plugin.MojoFailureException;
42 import org.apache.maven.project.MavenProject;
43 import org.codehaus.plexus.util.FileUtils;
44 import org.codehaus.plexus.util.StringUtils;
45 import org.eclipse.jetty.util.IO;
46 import org.eclipse.jetty.util.PatternMatcher;
47 import org.eclipse.jetty.util.resource.Resource;
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 public class JspcMojo extends AbstractMojo
80 {
81 public static final String END_OF_WEBAPP = "</web-app>";
82
83
84
85
86
87
88
89
90
91 private boolean useProvidedScope;
92
93
94
95
96
97
98
99
100 private Set projectArtifacts;
101
102
103
104
105
106
107
108
109
110 private MavenProject project;
111
112
113
114
115
116
117
118
119
120 private List pluginArtifacts;
121
122
123
124
125
126
127
128
129 private String webXmlFragment;
130
131
132
133
134
135
136
137
138
139
140 private String insertionMarker;
141
142
143
144
145
146
147
148
149 private boolean mergeFragment;
150
151
152
153
154
155
156 private String generatedClasses;
157
158
159
160
161
162
163
164 private boolean keepSources;
165
166
167
168
169
170
171 private String packageRoot;
172
173
174
175
176
177
178
179 private String webAppSourceDirectory;
180
181
182
183
184
185
186
187 private String webXml;
188
189
190
191
192
193
194
195
196 private String includes;
197
198
199
200
201
202
203 private String excludes;
204
205
206
207
208
209
210 private File classesDirectory;
211
212
213
214
215
216
217 private boolean verbose;
218
219
220
221
222
223
224 private boolean validateXml;
225
226
227
228
229
230
231 private String javaEncoding;
232
233
234
235
236
237
238 private boolean suppressSmap;
239
240
241
242
243
244
245 private boolean ignoreJspFragmentErrors;
246
247
248
249
250
251
252
253 private String schemaResourcePrefix;
254
255
256
257
258
259
260 private String tldJarNamePatterns;
261
262
263
264
265
266
267
268 private boolean trimSpaces = false;
269
270
271 public void execute() throws MojoExecutionException, MojoFailureException
272 {
273 if (getLog().isDebugEnabled())
274 {
275 getLog().info("verbose=" + verbose);
276 getLog().info("webAppSourceDirectory=" + webAppSourceDirectory);
277 getLog().info("generatedClasses=" + generatedClasses);
278 getLog().info("webXmlFragment=" + webXmlFragment);
279 getLog().info("webXml="+webXml);
280 getLog().info("validateXml=" + validateXml);
281 getLog().info("packageRoot=" + packageRoot);
282 getLog().info("javaEncoding=" + javaEncoding);
283 getLog().info("insertionMarker="+ (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker));
284 getLog().info("keepSources=" + keepSources);
285 getLog().info("mergeFragment=" + mergeFragment);
286 getLog().info("suppressSmap=" + suppressSmap);
287 getLog().info("ignoreJspFragmentErrors=" + ignoreJspFragmentErrors);
288 getLog().info("schemaResourcePrefix=" + schemaResourcePrefix);
289 getLog().info("trimSpaces=" + trimSpaces);
290 }
291 try
292 {
293 prepare();
294 compile();
295 cleanupSrcs();
296 mergeWebXml();
297 }
298 catch (Exception e)
299 {
300 throw new MojoExecutionException("Failure processing jsps", e);
301 }
302 }
303
304 public void compile() throws Exception
305 {
306 ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
307
308
309 List<URL> webAppUrls = setUpWebAppClassPath();
310
311
312 String sysClassPath = setUpSysClassPath();
313
314
315 List<URL> tldJarUrls = getSystemJarsWithTlds();
316
317 for (URL u:tldJarUrls)
318 {
319 if (getLog().isDebugEnabled())
320 getLog().debug(" sys jar with tlds: "+u);
321 webAppUrls.add(u);
322 }
323
324
325
326 URLClassLoader webAppClassLoader = new URLClassLoader((URL[]) webAppUrls.toArray(new URL[0]), currentClassLoader);
327 StringBuffer webAppClassPath = new StringBuffer();
328
329 for (int i = 0; i < webAppUrls.size(); i++)
330 {
331 if (getLog().isDebugEnabled())
332 getLog().debug("webappclassloader contains: " + webAppUrls.get(i));
333 webAppClassPath.append(new File(webAppUrls.get(i).toURI()).getCanonicalPath());
334 if (getLog().isDebugEnabled())
335 getLog().debug("added to classpath: " + ((URL) webAppUrls.get(i)).getFile());
336 if (i+1<webAppUrls.size())
337 webAppClassPath.append(System.getProperty("path.separator"));
338 }
339
340 Thread.currentThread().setContextClassLoader(webAppClassLoader);
341
342 JspC jspc = new JspC();
343 jspc.setWebXmlFragment(webXmlFragment);
344 jspc.setUriroot(webAppSourceDirectory);
345 jspc.setPackage(packageRoot);
346 jspc.setOutputDir(generatedClasses);
347 jspc.setValidateXml(validateXml);
348 jspc.setClassPath(webAppClassPath.toString());
349 jspc.setCompile(true);
350 jspc.setSmapSuppressed(suppressSmap);
351 jspc.setSmapDumped(!suppressSmap);
352 jspc.setJavaEncoding(javaEncoding);
353 jspc.setTrimSpaces(trimSpaces);
354 jspc.setSystemClassPath(sysClassPath);
355
356
357
358
359
360 String jspFiles = getJspFiles(webAppSourceDirectory);
361 getLog().info("Compiling "+jspFiles);
362 getLog().info("Includes="+includes);
363 getLog().info("Excludes="+excludes);
364 jspc.setJspFiles(jspFiles);
365 if (verbose)
366 {
367 getLog().info("Files selected to precompile: " + jspFiles);
368 }
369
370
371 try
372 {
373 jspc.setIgnoreJspFragmentErrors(ignoreJspFragmentErrors);
374 }
375 catch (NoSuchMethodError e)
376 {
377 getLog().debug("Tomcat Jasper does not support configuration option 'ignoreJspFragmentErrors': ignored");
378 }
379
380 try
381 {
382 if (schemaResourcePrefix != null)
383 jspc.setSchemaResourcePrefix(schemaResourcePrefix);
384 }
385 catch (NoSuchMethodError e)
386 {
387 getLog().debug("Tomcat Jasper does not support configuration option 'schemaResourcePrefix': ignored");
388 }
389 if (verbose)
390 jspc.setVerbose(99);
391 else
392 jspc.setVerbose(0);
393
394 jspc.execute();
395
396 Thread.currentThread().setContextClassLoader(currentClassLoader);
397 }
398
399 private String getJspFiles(String webAppSourceDirectory)
400 throws Exception
401 {
402 List fileNames = FileUtils.getFileNames(new File(webAppSourceDirectory),includes, excludes, false);
403 return StringUtils.join(fileNames.toArray(new String[0]), ",");
404
405 }
406
407
408
409
410
411
412
413 public void cleanupSrcs() throws Exception
414 {
415
416 if (!keepSources)
417 {
418 File generatedClassesDir = new File(generatedClasses);
419
420 if(generatedClassesDir.exists() && generatedClassesDir.isDirectory())
421 {
422 delete(generatedClassesDir, new FileFilter()
423 {
424 public boolean accept(File f)
425 {
426 return f.isDirectory() || f.getName().endsWith(".java");
427 }
428 });
429 }
430 }
431 }
432
433 static void delete(File dir, FileFilter filter)
434 {
435 File[] files = dir.listFiles(filter);
436 if (files != null)
437 {
438 for(File f: files)
439 {
440 if(f.isDirectory())
441 delete(f, filter);
442 else
443 f.delete();
444 }
445 }
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459 public void mergeWebXml() throws Exception
460 {
461 if (mergeFragment)
462 {
463
464 File webXml = getWebXmlFile();
465
466 if (!webXml.exists())
467 {
468 getLog().info(webXml.toString() + " does not exist, cannot merge with generated fragment");
469 return;
470 }
471
472 File fragmentWebXml = new File(webXmlFragment);
473 if (!fragmentWebXml.exists())
474 {
475 getLog().info("No fragment web.xml file generated");
476 }
477 File mergedWebXml = new File(fragmentWebXml.getParentFile(),
478 "web.xml");
479 try (BufferedReader webXmlReader = new BufferedReader(new FileReader(
480 webXml));
481 PrintWriter mergedWebXmlWriter = new PrintWriter(new FileWriter(
482 mergedWebXml))) {
483
484
485
486 boolean atInsertPoint = false;
487 boolean atEOF = false;
488 String marker = (insertionMarker == null
489 || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker);
490 while (!atInsertPoint && !atEOF)
491 {
492 String line = webXmlReader.readLine();
493 if (line == null)
494 atEOF = true;
495 else if (line.indexOf(marker) >= 0)
496 {
497 atInsertPoint = true;
498 }
499 else
500 {
501 mergedWebXmlWriter.println(line);
502 }
503 }
504
505
506 try (BufferedReader fragmentWebXmlReader = new BufferedReader(
507 new FileReader(fragmentWebXml))) {
508 IO.copy(fragmentWebXmlReader, mergedWebXmlWriter);
509
510
511 if (marker.equals(END_OF_WEBAPP))
512 mergedWebXmlWriter.println(END_OF_WEBAPP);
513
514
515 IO.copy(webXmlReader, mergedWebXmlWriter);
516 }
517 }
518 }
519 }
520
521 private void prepare() throws Exception
522 {
523
524
525 File generatedSourceDirectoryFile = new File(generatedClasses);
526 if (!generatedSourceDirectoryFile.exists())
527 generatedSourceDirectoryFile.mkdirs();
528 }
529
530
531
532
533
534
535
536
537
538
539 private List<URL> setUpWebAppClassPath() throws Exception
540 {
541
542 List<URL> urls = new ArrayList<URL>();
543 String classesDir = classesDirectory.getCanonicalPath();
544 classesDir = classesDir + (classesDir.endsWith(File.pathSeparator) ? "" : File.separator);
545 urls.add(Resource.toURL(new File(classesDir)));
546
547 if (getLog().isDebugEnabled())
548 getLog().debug("Adding to classpath classes dir: " + classesDir);
549
550
551 for (Iterator<Artifact> iter = project.getArtifacts().iterator(); iter.hasNext();)
552 {
553 Artifact artifact = (Artifact)iter.next();
554
555
556 if (!Artifact.SCOPE_TEST.equals(artifact.getScope()) && !Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
557 {
558 String filePath = artifact.getFile().getCanonicalPath();
559 if (getLog().isDebugEnabled())
560 getLog().debug("Adding to classpath dependency file: " + filePath);
561
562 urls.add(Resource.toURL(artifact.getFile()));
563 }
564 }
565 return urls;
566 }
567
568
569 private String setUpSysClassPath () throws Exception
570 {
571 StringBuffer buff = new StringBuffer();
572
573
574 for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext(); )
575 {
576 Artifact pluginArtifact = iter.next();
577 if ("jar".equalsIgnoreCase(pluginArtifact.getType()))
578 {
579 if (getLog().isDebugEnabled()) { getLog().debug("Adding plugin artifact "+pluginArtifact);}
580 buff.append(pluginArtifact.getFile().getAbsolutePath());
581 if (iter.hasNext())
582 buff.append(File.pathSeparator);
583 }
584 }
585
586
587 if (useProvidedScope)
588 {
589 for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
590 {
591 Artifact artifact = iter.next();
592 if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
593 {
594
595 String path = artifact.getFile().getAbsolutePath();
596 if (! buff.toString().contains(path))
597 {
598 if (buff.length() != 0)
599 buff.append(File.pathSeparator);
600 buff.append(path);
601 if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
602 }
603 else
604 {
605 if (getLog().isDebugEnabled()) { getLog().debug("Skipping provided artifact: "+artifact);}
606 }
607 }
608 }
609 }
610
611 return buff.toString();
612 }
613
614
615
616
617
618
619
620
621
622
623
624 private List<URL> getSystemJarsWithTlds() throws Exception
625 {
626 final List<URL> list = new ArrayList<URL>();
627 List<URI> artifactUris = new ArrayList<URI>();
628 Pattern pattern = Pattern.compile(tldJarNamePatterns);
629 for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext(); )
630 {
631 Artifact pluginArtifact = iter.next();
632 artifactUris.add(Resource.newResource(pluginArtifact.getFile()).getURI());
633 }
634
635 PatternMatcher matcher = new PatternMatcher()
636 {
637 public void matched(URI uri) throws Exception
638 {
639
640 list.add(uri.toURL());
641 }
642 };
643 matcher.match(pattern, artifactUris.toArray(new URI[artifactUris.size()]), false);
644
645 return list;
646 }
647
648 private File getWebXmlFile ()
649 throws IOException
650 {
651 File file = null;
652 File baseDir = project.getBasedir().getCanonicalFile();
653 File defaultWebAppSrcDir = new File (baseDir, "src/main/webapp").getCanonicalFile();
654 File webAppSrcDir = new File (webAppSourceDirectory).getCanonicalFile();
655 File defaultWebXml = new File (defaultWebAppSrcDir, "web.xml").getCanonicalFile();
656
657
658 File webXmlFile = new File (webXml).getCanonicalFile();
659 if (webXmlFile.compareTo(defaultWebXml) != 0)
660 {
661 file = new File (webXml);
662 return file;
663 }
664
665
666
667 file = new File (webAppSrcDir, "web.xml");
668 return file;
669 }
670 }