View Javadoc

1   /*
2    *  jDTAUS Core Container Mojo
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.core.container.mojo;
22  
23  import java.io.BufferedReader;
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileOutputStream;
27  import java.io.FileReader;
28  import java.io.FileWriter;
29  import java.io.IOException;
30  import java.io.InputStreamReader;
31  import java.io.OutputStreamWriter;
32  import java.io.StringReader;
33  import java.io.StringWriter;
34  import java.io.Writer;
35  import java.net.MalformedURLException;
36  import java.net.URL;
37  import java.util.Arrays;
38  import java.util.Collection;
39  import java.util.HashSet;
40  import java.util.Iterator;
41  import java.util.LinkedList;
42  import java.util.List;
43  import java.util.Locale;
44  import java.util.Set;
45  import org.apache.maven.artifact.Artifact;
46  import org.apache.maven.artifact.DependencyResolutionRequiredException;
47  import org.apache.maven.plugin.AbstractMojo;
48  import org.apache.maven.plugin.MojoFailureException;
49  import org.apache.maven.project.MavenProject;
50  import org.apache.velocity.app.VelocityEngine;
51  import org.codehaus.plexus.util.DirectoryScanner;
52  import org.jdtaus.core.container.mojo.model.ModelManager;
53  
54  /**
55   * jDTAUS Container Mojo base implementation.
56   *
57   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
58   * @version $JDTAUS: AbstractContainerMojo.java 8743 2012-10-07 03:06:20Z schulte $
59   */
60  public abstract class AbstractContainerMojo extends AbstractMojo
61  {
62      //--Configuration-----------------------------------------------------------
63  
64      /**
65       * Name of the system property controlling the use of the context
66       * classloader.
67       */
68      private static final String SYS_ENABLE_CONTEXT_CLASSLOADER =
69          "org.jdtaus.core.container.ClassLoaderFactory.enableContextClassloader";
70  
71      /**
72       * @parameter expression="${project}"
73       * @required
74       * @readonly
75       */
76      private MavenProject mavenProject;
77  
78      /**
79       * Number of spaces to use per indentation level.
80       * @parameter expression="${spacesPerIndentationLevel}" default-value="4"
81       * @optional
82       */
83      private Integer spacesPerIndentationLevel;
84  
85      /**
86       * The encoding to use for reading and writing sources. By default the
87       * system's default encoding will be used.
88       * @parameter expression="${encoding}"
89       *            default-value="${project.build.sourceEncoding}"
90       * @optional
91       */
92      private String encoding;
93  
94      /**
95       * Flag indicating test mode. In test mode generated sources will be
96       * printed to the console and no files will be written.
97       * @parameter expression="${testMode}" default-value="false"
98       * @optional
99       */
100     private Boolean testMode;
101 
102     /**
103      * Language to be used for javadoc comments. By default the system's
104      * default locale will be used.
105      * @parameter expression="${locale}"
106      * @optional
107      */
108     private String locale;
109 
110     /**
111      * A regular expression used for excluding elements from the runtime
112      * classpath elements. By default no elements will be excluded.
113      * @parameter expression="${classPathElementsExcludeRegexp}"
114      * @optional
115      */
116     private String classPathElementsExcludeRegexp;
117 
118     /**
119      * A regular expression used for excluding elements from the test
120      * classpath elements. By default no elements will be excluded.
121      * @parameter expression="${testClassPathElementsExcludeRegexp}"
122      * @optional
123      */
124     private String testClassPathElementsExcludeRegexp;
125 
126     /** @component */
127     private ModelManager modelManager;
128 
129     /**
130      * Getter for property {@code encoding}.
131      *
132      * @return the encoding to use for reading and writing sources or
133      * {@code null} to use the system's default encoding.
134      */
135     protected final String getEncoding()
136     {
137         return this.encoding;
138     }
139 
140     /**
141      * Accessor to the currently executed {@code MavenProject}.
142      *
143      * @return the currently executed {@code MavenProject}.
144      */
145     protected final MavenProject getMavenProject()
146     {
147         return this.mavenProject;
148     }
149 
150     /**
151      * Getter for property {@code testMode}.
152      *
153      * @return {@code true} if no sources will be touched; {@code false} if
154      * sources will be changed.
155      */
156     protected final boolean isTestMode()
157     {
158         return this.testMode.booleanValue();
159     }
160 
161     /**
162      * Getter for property {@code locale}.
163      *
164      * @return the locale to use for javadoc comments.
165      */
166     protected final Locale getLocale()
167     {
168         return this.locale == null
169                ? Locale.getDefault()
170                : new Locale( this.locale );
171 
172     }
173 
174     /**
175      * Accessor to the project's classpath elements including runtime
176      * dependencies.
177      *
178      * @return a set of class path element strings.
179      *
180      * @throws DependencyResolutionRequiredException for any unresolved
181      * dependency scopes.
182      */
183     protected final Set getClasspathElements()
184         throws DependencyResolutionRequiredException
185     {
186         final Set elements = new HashSet();
187 
188         elements.add( this.getMavenProject().getBuild().getOutputDirectory() );
189 
190         int i = 0;
191         for ( final Iterator it = this.getMavenProject().getRuntimeArtifacts().
192             iterator(); it.hasNext(); )
193         {
194             final Artifact a = (Artifact) it.next();
195 
196             if ( a.getFile() == null )
197             {
198                 this.getLog().warn( a.toString() + " ignored." );
199                 continue;
200             }
201 
202             final String element = a.getFile().getAbsolutePath();
203 
204             if ( this.getLog().isDebugEnabled() )
205             {
206                 this.getLog().debug( "Runtime classpath element[" + i++ +
207                                      "]: " + element );
208 
209             }
210 
211             elements.add( element );
212         }
213 
214         i = 0;
215         for ( final Iterator it = this.getMavenProject().getCompileArtifacts().
216             iterator(); it.hasNext(); )
217         {
218             final Artifact a = (Artifact) it.next();
219 
220             if ( a.getFile() == null )
221             {
222                 this.getLog().warn( a.toString() + " ignored." );
223                 continue;
224             }
225 
226             final String element = a.getFile().getAbsolutePath();
227 
228             if ( this.getLog().isDebugEnabled() )
229             {
230                 this.getLog().debug( "Compile classpath element[" + i++ +
231                                      "]: " + element );
232 
233             }
234 
235             elements.add( element );
236         }
237 
238         return elements;
239     }
240 
241     /**
242      * Accessor to the test classpath elements.
243      *
244      * @return a set of class path element strings.
245      *
246      * @throws DependencyResolutionRequiredException for any unresolved
247      * dependency scopes.
248      */
249     protected final Set getTestClasspathElements()
250         throws DependencyResolutionRequiredException
251     {
252         final Set elements = new HashSet();
253 
254         elements.add( this.getMavenProject().getBuild().getOutputDirectory() );
255         elements.add( this.getMavenProject().getBuild().
256             getTestOutputDirectory() );
257 
258         int i = 0;
259         for ( final Iterator it = this.getMavenProject().getTestArtifacts().
260             iterator(); it.hasNext(); )
261         {
262             final Artifact a = (Artifact) it.next();
263 
264             if ( a.getFile() == null )
265             {
266                 this.getLog().warn( a.toString() + " ignored." );
267                 continue;
268             }
269 
270             final String element = a.getFile().getAbsolutePath();
271 
272             if ( this.getLog().isDebugEnabled() )
273             {
274                 this.getLog().debug( "Test classpath element[" + i++ +
275                                      "]: " + element );
276 
277             }
278 
279             elements.add( element );
280         }
281 
282         return elements;
283     }
284 
285     /**
286      * Indicates wheter a class path element should be included in the
287      * classpath.
288      *
289      * @param element the element to check for classpath inclusion.
290      *
291      * @return {@code true} if {@code element} should be included in the
292      * classpath; {@code false} if not.
293      *
294      * @throws NullPointerException if {@code element} is {@code null}.
295      */
296     protected boolean isClasspathElementIncluded( final String element )
297     {
298         if ( element == null )
299         {
300             throw new NullPointerException( "element" );
301         }
302 
303         boolean ret = !this.isClasspathElementDefaultExlude( element );
304 
305         if ( ret && this.classPathElementsExcludeRegexp != null )
306         {
307             ret = !element.matches( this.classPathElementsExcludeRegexp );
308         }
309 
310         return ret;
311     }
312 
313     /**
314      * Indicates wheter a class path element should be included in the
315      * classpath.
316      *
317      * @param element the element to check for classpath inclusion.
318      *
319      * @return {@code true} if {@code element} should be included in the
320      * classpath; {@code false} if not.
321      *
322      * @throws NullPointerException if {@code element} is {@code null}.
323      */
324     protected boolean isTestClasspathElementIncluded( final String element )
325     {
326         if ( element == null )
327         {
328             throw new NullPointerException( "element" );
329         }
330 
331         boolean ret = !this.isClasspathElementDefaultExlude( element );
332 
333         if ( ret && this.testClassPathElementsExcludeRegexp != null )
334         {
335             ret = !element.matches( this.testClassPathElementsExcludeRegexp );
336         }
337 
338         return ret;
339     }
340 
341     /**
342      * Indicates whether a class path element is on the list of default class
343      * path element excludes.
344      *
345      * @param element the element to check for default classpath exclusion.
346      *
347      * @return {@code true} if {@code element} should be excluded by default;
348      * {@code false} if not.
349      *
350      * @throws NullPointerException if {@code element} is {@code null}.
351      */
352     protected boolean isClasspathElementDefaultExlude( final String element )
353     {
354         return false;
355     }
356 
357     /** Default source include patterns. */
358     protected static final String[] DEFAULT_SOURCE_INCLUDES =
359     {
360         "**/*.java",
361         "**/*.xml",
362         "**/*.xsd",
363         "**/*.html",
364         "**/*.vm",
365         "**/*.apt"
366     };
367 
368     /**
369      * Gets the {@code ModelManager} instance.
370      *
371      * @return the {@code ModelManager} instance.
372      */
373     protected ModelManager getModelManager()
374     {
375         return this.modelManager;
376     }
377 
378     //-----------------------------------------------------------Configuration--
379     //--AbstractContainerMojo---------------------------------------------------
380 
381     /** Name of the velocity classpath resource loader implementation. */
382     private static final String VELOCITY_RESOURCE_LOADER =
383         "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader";
384 
385     /** {@code VelocityEngine}. */
386     private VelocityEngine velocityEngine;
387 
388     /** Interface to manipulate source files. */
389     public interface SourceEditor
390     {
391 
392         /**
393          * Replaces a line in a source file with some string.
394          *
395          * @param line next line of the currently edited source file or
396          * {@code null} if the end of the file has been reached.
397          *
398          * @return the string to replace {@code line} with or {@code null}
399          * to replace {@code line} with nothing.
400          *
401          * @throws MojoFailureException for unrecoverable errors.
402          */
403         String editLine( String line ) throws MojoFailureException;
404 
405         /**
406          * Flag indicating that the editor changed a line.
407          *
408          * @return {@code true} if the editor changed a line of input;
409          * {@code false} if not.
410          */
411         boolean isModified();
412 
413     }
414 
415     /**
416      * Accessor to a {@code *.java} file for a given class name.
417      *
418      * @param roots list of source roots to search.
419      * @param className The class name to return the corresponding
420      * {@code *.java} file for (needs to be in the project's compile source
421      * roots). No inner classes are supported yet.
422      *
423      * @return the source file for the class with name {@code className} or
424      * {@code null} if no corresponding source file can be found.
425      *
426      * @throws NullPointerException if either {@code roots} or {@code className}
427      * is {@code null}.
428      */
429     protected final File getSource( final List roots, final String className )
430     {
431         if ( className == null )
432         {
433             throw new NullPointerException( "className" );
434         }
435         if ( roots == null )
436         {
437             throw new NullPointerException( "roots" );
438         }
439 
440         File file;
441         String source;
442         File ret = null;
443         final String fileName =
444             className.replace( '.', File.separatorChar ).concat( ".java" );
445 
446         for ( final Iterator it = roots.iterator(); it.hasNext(); )
447         {
448             source = (String) it.next();
449             file =
450                 new File( source.concat( File.separator ).concat( fileName ) );
451 
452             if ( file.canRead() && file.canWrite() )
453             {
454                 ret = file;
455                 break;
456             }
457             else
458             {
459                 ret = null;
460             }
461         }
462 
463         return ret;
464     }
465 
466     /**
467      * Gets all source files from the project's compile source roots.
468      *
469      * @return a {@code Collection} holding {@code File} instances for all
470      * source files found in all compile source roots.
471      */
472     protected final Collection getAllSources()
473     {
474         File file;
475         File parentRoot;
476         String sourceRoot;
477         DirectoryScanner scanner;
478         final Collection files = new LinkedList();
479 
480         for ( final Iterator it = this.getMavenProject().
481             getCompileSourceRoots().iterator(); it.hasNext(); )
482         {
483             sourceRoot = (String) it.next();
484             parentRoot = new File( sourceRoot );
485 
486             if ( !parentRoot.exists() || !parentRoot.isDirectory() )
487             {
488                 continue;
489             }
490 
491             scanner = new DirectoryScanner();
492             scanner.setBasedir( sourceRoot );
493             scanner.setIncludes( DEFAULT_SOURCE_INCLUDES );
494             scanner.addDefaultExcludes();
495             scanner.scan();
496 
497             for ( final Iterator it2 =
498                 Arrays.asList( scanner.getIncludedFiles() ).iterator();
499                   it2.hasNext(); )
500             {
501                 file = new File( parentRoot, (String) it2.next() );
502                 files.add( file );
503             }
504         }
505 
506         return files;
507     }
508 
509     /**
510      * Gets all source files from the project's test compile source roots.
511      *
512      * @return a {@code Collection} holding {@code File} instances for all
513      * source files found in all test compile source roots.
514      */
515     protected final Collection getTestSources()
516     {
517         File file;
518         File parentRoot;
519         String sourceRoot;
520         DirectoryScanner scanner;
521         final Collection files = new LinkedList();
522 
523         for ( final Iterator it = this.getMavenProject().
524             getTestCompileSourceRoots().iterator(); it.hasNext(); )
525         {
526             sourceRoot = (String) it.next();
527             parentRoot = new File( sourceRoot );
528 
529             if ( !parentRoot.exists() || !parentRoot.isDirectory() )
530             {
531                 continue;
532             }
533 
534             scanner = new DirectoryScanner();
535             scanner.setBasedir( sourceRoot );
536             scanner.setIncludes( DEFAULT_SOURCE_INCLUDES );
537             scanner.addDefaultExcludes();
538             scanner.scan();
539 
540             for ( final Iterator it2 =
541                 Arrays.asList( scanner.getIncludedFiles() ).iterator();
542                   it2.hasNext(); )
543             {
544                 file = new File( parentRoot, (String) it2.next() );
545                 files.add( file );
546             }
547         }
548 
549         return files;
550     }
551 
552     /**
553      * Edits a string.
554      *
555      * @param str The string to edit.
556      * @param editor The editor to use for editing {@code str}.
557      *
558      * @return {@code str} edited by {@code editor}.
559      *
560      * @throws NullPointerException if either {@code str} or {@code editor} is
561      * {@code null}.
562      * @throws MojoFailureException for unrecoverable errors.
563      */
564     protected final String edit(
565         final String str, final AbstractContainerMojo.SourceEditor editor )
566         throws MojoFailureException
567     {
568         if ( str == null )
569         {
570             throw new NullPointerException( "str" );
571         }
572         if ( editor == null )
573         {
574             throw new NullPointerException( "editor" );
575         }
576 
577         int i;
578         String line;
579         String replacement;
580         final char[] chars;
581         final BufferedReader reader;
582         final StringWriter writer = new StringWriter();
583 
584         try
585         {
586             reader = new BufferedReader( new StringReader( str ) );
587 
588             while ( ( line = reader.readLine() ) != null )
589             {
590                 replacement = editor.editLine( line );
591                 if ( replacement != null )
592                 {
593                     writer.write( replacement.concat( "\n" ) );
594                 }
595             }
596 
597             replacement = editor.editLine( null );
598             if ( replacement != null )
599             {
600                 writer.write( replacement.concat( "\n" ) );
601             }
602 
603             reader.close();
604             writer.close();
605 
606             replacement = writer.toString();
607             chars = replacement.toCharArray();
608 
609             // Remove trailing newlines.
610             for ( i = chars.length - 1; i >= 0; i-- )
611             {
612                 if ( chars[i] != '\n' && chars[i] != '\r' )
613                 {
614                     break;
615                 }
616             }
617 
618             replacement = replacement.substring( 0, i + 1 );
619             return replacement + '\n';
620 
621         }
622         catch ( final IOException e )
623         {
624             final MojoFailureException mfe =
625                 new MojoFailureException( e.getMessage() );
626 
627             mfe.initCause( e );
628             throw mfe;
629         }
630     }
631 
632     /**
633      * Loads the contents of a file.
634      *
635      * @param file The file to load.
636      *
637      * @return the contents of {@code file}.
638      *
639      * @throws NullPointerException if {@code file} is {@code null}.
640      * @throws MojoFailureException for unrecoverable errors.
641      */
642     protected final String load( final File file ) throws
643         MojoFailureException
644     {
645         if ( file == null )
646         {
647             throw new NullPointerException( "file" );
648         }
649 
650         String line;
651         BufferedReader reader = null;
652         StringWriter writer = null;
653 
654         try
655         {
656             if ( this.getEncoding() == null )
657             {
658                 reader = new BufferedReader( new FileReader( file ) );
659             }
660             else
661             {
662                 reader = new BufferedReader( new InputStreamReader(
663                     new FileInputStream( file ),
664                     this.getEncoding() ) );
665 
666             }
667 
668             writer = new StringWriter();
669 
670             while ( ( line = reader.readLine() ) != null )
671             {
672                 writer.write( line.concat( "\n" ) );
673             }
674 
675             reader.close();
676             reader = null;
677 
678             writer.close();
679 
680             final String content = writer.toString();
681             writer = null;
682 
683             return content;
684         }
685         catch ( final IOException e )
686         {
687             final MojoFailureException mfe =
688                 new MojoFailureException( e.getMessage() );
689 
690             mfe.initCause( e );
691             throw mfe;
692         }
693         finally
694         {
695             try
696             {
697                 if ( reader != null )
698                 {
699                     reader.close();
700                 }
701             }
702             catch ( final IOException e )
703             {
704                 this.getLog().error( e );
705             }
706             finally
707             {
708                 try
709                 {
710                     if ( writer != null )
711                     {
712                         writer.close();
713                     }
714                 }
715                 catch ( final IOException e )
716                 {
717                     this.getLog().error( e );
718                 }
719             }
720         }
721     }
722 
723     /**
724      * Saves a string to a file.
725      *
726      * @param file The file to save {@code str} to.
727      * @param str The string to save to {@code file}.
728      *
729      * @throws NullPointerException if either {@code file} or {@code str} is
730      * {@code null}.
731      * @throws MojoFailureException for unrecoverable errors.
732      */
733     protected final void save( final File file, final String str ) throws
734         MojoFailureException
735     {
736         if ( file == null )
737         {
738             throw new NullPointerException( "file" );
739         }
740         if ( str == null )
741         {
742             throw new NullPointerException( "str" );
743         }
744 
745         Writer fileWriter = null;
746 
747         try
748         {
749             if ( this.isTestMode() )
750             {
751                 this.getLog().info( str );
752             }
753             else
754             {
755                 if ( this.getEncoding() == null )
756                 {
757                     fileWriter = new FileWriter( file );
758                 }
759                 else
760                 {
761                     fileWriter = new OutputStreamWriter(
762                         new FileOutputStream( file ), this.getEncoding() );
763 
764                 }
765 
766                 this.getLog().info( AbstractContainerMojoBundle.getInstance().
767                     getFileInfoMessage( Locale.getDefault(), file.getName() ) );
768 
769                 fileWriter.write( str );
770                 fileWriter.close();
771                 fileWriter = null;
772             }
773         }
774         catch ( final IOException e )
775         {
776             final MojoFailureException mfe =
777                 new MojoFailureException( e.getMessage() );
778 
779             mfe.initCause( e );
780             throw mfe;
781         }
782         finally
783         {
784             try
785             {
786                 if ( fileWriter != null )
787                 {
788                     fileWriter.close();
789                 }
790             }
791             catch ( final IOException e )
792             {
793                 this.getLog().error( e );
794             }
795         }
796     }
797 
798     /**
799      * Adds the configured number of spaces to a string buffer.
800      *
801      * @param stringBuffer The {@code StringBuffer} to add the number of spaces
802      * to.
803      *
804      * @throws NullPointerException if {@code stringBuffer} is {@code null}.
805      */
806     protected final void indent( final StringBuffer stringBuffer )
807     {
808         if ( stringBuffer == null )
809         {
810             throw new NullPointerException( "stringBuffer" );
811         }
812 
813         final char[] spaces =
814                      new char[ this.spacesPerIndentationLevel.intValue() ];
815 
816         Arrays.fill( spaces, ' ' );
817         stringBuffer.append( spaces );
818     }
819 
820     /**
821      * Provides access to the project's runtime classpath.
822      *
823      * @param parent the parent classloader to use for the runtime classloader.
824      *
825      * @return a {@code ClassLoader} initialized with the project's runtime
826      * classpath.
827      *
828      * @throws MojoFailureException for unrecoverable technical errors.
829      */
830     protected final ClassLoader getRuntimeClassLoader(
831         final ClassLoader parent ) throws MojoFailureException
832     {
833         final Collection urls = new LinkedList();
834 
835         try
836         {
837             int i = 0;
838             for ( final Iterator it = this.getClasspathElements().
839                 iterator(); it.hasNext(); )
840             {
841                 final String element = (String) it.next();
842                 final URL url = new File( element ).toURI().toURL();
843 
844                 if ( !urls.contains( url )
845                      && this.isClasspathElementIncluded( element ) )
846                 {
847                     urls.add( url );
848 
849                     if ( this.getLog().isDebugEnabled() )
850                     {
851                         this.getLog().debug( "runtime[" + i++ + "]="
852                                              + url.toExternalForm() );
853 
854                     }
855                 }
856             }
857 
858             return new ResourceLoader(
859                 (URL[]) urls.toArray( new URL[ urls.size() ] ), parent );
860 
861         }
862         catch ( final DependencyResolutionRequiredException e )
863         {
864             final MojoFailureException mfe =
865                 new MojoFailureException( e.getMessage() );
866 
867             mfe.initCause( e );
868             throw mfe;
869         }
870         catch ( final MalformedURLException e )
871         {
872             final MojoFailureException mfe =
873                 new MojoFailureException( e.getMessage() );
874 
875             mfe.initCause( e );
876             throw mfe;
877         }
878     }
879 
880     /**
881      * Provides access to the project's test classpath.
882      *
883      * @param parent the parent classloader to use for the test classloader.
884      *
885      * @return a {@code ClassLoader} initialized with the project's test
886      * classpath.
887      *
888      * @throws MojoFailureException for unrecoverable technical errors.
889      */
890     protected final ClassLoader getTestClassLoader( final ClassLoader parent )
891         throws MojoFailureException
892     {
893         final Iterator it;
894         final Collection urls = new LinkedList();
895 
896         try
897         {
898             int i = 0;
899             for ( it = this.getTestClasspathElements().iterator();
900                   it.hasNext(); )
901             {
902                 final String element = (String) it.next();
903                 final URL url = new File( element ).toURI().toURL();
904                 if ( !urls.contains( url ) &&
905                      this.isTestClasspathElementIncluded( element ) )
906                 {
907                     urls.add( url );
908 
909                     if ( this.getLog().isDebugEnabled() )
910                     {
911                         this.getLog().debug( "test[" + i++ + "]=" +
912                                              url.toExternalForm() );
913 
914                     }
915                 }
916             }
917 
918             return new ResourceLoader(
919                 (URL[]) urls.toArray( new URL[ urls.size() ] ), parent );
920 
921         }
922         catch ( final MalformedURLException e )
923         {
924             final MojoFailureException mfe =
925                 new MojoFailureException( e.getMessage() );
926 
927             mfe.initCause( e );
928             throw mfe;
929         }
930         catch ( final DependencyResolutionRequiredException e )
931         {
932             final MojoFailureException mfe =
933                 new MojoFailureException( e.getMessage() );
934 
935             mfe.initCause( e );
936             throw mfe;
937         }
938     }
939 
940     /**
941      * Gets the {@code VelocityEngine} used for generating source code.
942      *
943      * @return the {@code VelocityEngine} used for generating source code.
944      *
945      * @throws Exception if initializing a new velocity engine fails.
946      */
947     protected final VelocityEngine getVelocity() throws Exception
948     {
949         if ( this.velocityEngine == null )
950         {
951             final VelocityEngine engine = new VelocityEngine();
952             final java.util.Properties props = new java.util.Properties();
953             props.put( "resource.loader", "class" );
954             props.put( "class.resource.loader.class",
955                        VELOCITY_RESOURCE_LOADER );
956 
957             engine.init( props );
958             this.velocityEngine = engine;
959         }
960 
961         return this.velocityEngine;
962     }
963 
964     /**
965      * Formats a given text to a javadoc comment.
966      *
967      * @param text The text to format.
968      *
969      * @return {@code text} as a javadoc comment.
970      *
971      * @throws NullPointerException if {@code text} is {@code null}.
972      */
973     protected String formatComment( final String text )
974     {
975         if ( text == null )
976         {
977             throw new NullPointerException( "text" );
978         }
979 
980         String normalized = text.replaceAll( "\\/\\*\\*", "/*" );
981         normalized = normalized.replaceAll( "\\*/", "/" );
982 
983         final StringBuffer commentLinebreak = new StringBuffer();
984         commentLinebreak.append( '\n' );
985         this.indent( commentLinebreak );
986         commentLinebreak.append( " *" );
987 
988         normalized =
989         normalized.replaceAll( "\n", commentLinebreak.toString() );
990 
991         return normalized;
992     }
993 
994     /**
995      * Enables the use of the thread context classloader by setting system
996      * property {@code org.jdtaus.core.container.ClassLoaderFactory.enableContextClassloader}
997      * to {@code true}.
998      */
999     protected static void enableThreadContextClassLoader()
1000     {
1001         System.setProperty( SYS_ENABLE_CONTEXT_CLASSLOADER,
1002                             Boolean.toString( true ) );
1003 
1004     }
1005 
1006     /**
1007      * Disables the use of the thread context classloader by setting system
1008      * property {@code org.jdtaus.core.container.ClassLoaderFactory.enableContextClassloader}
1009      * to {@code true}.
1010      */
1011     protected static void disableThreadContextClassLoader()
1012     {
1013         System.setProperty( SYS_ENABLE_CONTEXT_CLASSLOADER,
1014                             Boolean.toString( false ) );
1015 
1016     }
1017 
1018     //---------------------------------------------------AbstractContainerMojo--
1019 }