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