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