1 package org.apache.maven;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import org.apache.commons.jelly.JellyContext;
22 import org.apache.commons.jelly.expression.CompositeExpression;
23 import org.apache.commons.jelly.expression.Expression;
24 import org.apache.commons.jelly.expression.jexl.JexlExpressionFactory;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.maven.jelly.JellyUtils;
28 import org.apache.maven.jelly.MavenJellyContext;
29 import org.apache.maven.project.Project;
30 import org.apache.tools.ant.DirectoryScanner;
31 import org.codehaus.plexus.util.CollectionUtils;
32 import org.codehaus.plexus.util.StringUtils;
33 import org.xml.sax.SAXException;
34
35 import com.werken.forehead.ForeheadClassLoader;
36
37 import java.beans.IntrospectionException;
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileNotFoundException;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.StringReader;
44 import java.net.URL;
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.HashMap;
48 import java.util.Iterator;
49 import java.util.List;
50 import java.util.Locale;
51 import java.util.Map;
52 import java.util.MissingResourceException;
53 import java.util.Properties;
54 import java.util.ResourceBundle;
55 import java.util.Set;
56 import java.util.StringTokenizer;
57
58 import javax.xml.parsers.ParserConfigurationException;
59
60 /**
61 * Utilities for reading maven project descriptors, profile descriptors and workspace descriptors.
62 *
63 * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
64 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
65 *
66 * @todo Remove all the context creation code and make a ContextBuilder class.
67 * @todo [RC2] split getProject (project.properties + defaults) != getPluginProject (plugin.properties only)
68 */
69 public class MavenUtils
70 {
71 /** Log. */
72 private static final Log LOGGER = LogFactory.getLog( MavenUtils.class );
73
74 /** Map of loaded POMs. */
75 private static HashMap parentPoms = new HashMap();
76
77 /** Maven unknown error message. */
78 public static final String MAVEN_UNKNOWN_ERROR = "Unknown error reading project";
79
80 /**
81 * Create a Project object given a file descriptor.
82 *
83 * @param projectDescriptor
84 * a maven project.xml
85 * @return the Maven project object for the given project descriptor
86 * @throws MavenException
87 * when any errors occur
88 */
89 public static Project getProject( File projectDescriptor ) throws MavenException
90 {
91 return getProject( projectDescriptor, null );
92 }
93
94 /**
95 * Create a Project object given a file descriptor, and a parent context
96 *
97 * @param projectDescriptor
98 * The file to create the project from
99 * @param parentContext
100 * the parent Maven Jelly Context
101 * @return a new Project
102 * @throws MavenException
103 * when any error happens.
104 */
105 public static Project getProject( File projectDescriptor, MavenJellyContext parentContext ) throws MavenException
106 {
107 return getProject( projectDescriptor, parentContext, true );
108 }
109
110 /**
111 * Create a Project object given a file descriptor and optionally a parent Jelly context.
112 *
113 * @param projectDescriptor
114 * a maven project.xml {@link File}
115 * @param parentContext
116 * the parent context for the new project
117 * @param useParentPom
118 * whether a parent project should be respected
119 * @return the MavenSession project object for the given project descriptor
120 * @throws MavenException
121 * when any errors occur
122 */
123 public static Project getProject( File projectDescriptor, MavenJellyContext parentContext, boolean useParentPom )
124 throws MavenException
125 {
126 Project project = null;
127 try
128 {
129 project = getNonJellyProject( projectDescriptor, parentContext, useParentPom );
130 project = getJellyProject( project );
131 project.setFile( projectDescriptor );
132
133
134 project.initialize();
135 }
136 catch ( IntrospectionException e )
137 {
138 throw new MavenException( "Error creating a string from the project", e );
139 }
140 catch ( IOException e )
141 {
142 throw new MavenException( "Error reading XML or initializing", e );
143 }
144 catch ( ParserConfigurationException e )
145 {
146 throw new MavenException( "Error creating a JAXP Parser", e );
147 }
148 catch ( SAXException e )
149 {
150 throw new MavenException( "Error parsing XML", e );
151 }
152 catch ( MavenException e )
153 {
154 throw e;
155 }
156 catch ( Exception e )
157 {
158
159 throw new MavenException( MAVEN_UNKNOWN_ERROR, e );
160 }
161
162 return project;
163 }
164
165 /**
166 * Get a project, but not a Jelly-ised project. ie Don't evaluate the variables. We are doing several things when
167 * creating a POM object, the phases are outlined here:
168 *
169 * 1) The project.xml file is read in using betwixt which creates for us a Project object that, at this point, has
170 * not been run through Jelly i.e. no interpolation has occured yet.
171 *
172 * 2) The context for the project is created and set. So each project manages its own context. See the
173 * createContext() method for the details context creation process.
174 *
175 * 3) We check to see if the <extend> tag is being employed. If so, the parent project.xml file is read in. At
176 * this point we have a child and parent POM and the values are merged where the child's values override those of
177 * the parent.
178 *
179 * @param projectDescriptor
180 * the project file
181 * @param parentContext
182 * the parent context for the new project
183 * @param useParentPom
184 * whether a parent project should be respected
185 * @return the project
186 * @throws MavenException
187 * when there are errors reading the descriptor
188 * @throws IOException
189 * when resolving file names and paths
190 */
191 public static Project getNonJellyProject( File projectDescriptor, MavenJellyContext parentContext,
192 boolean useParentPom ) throws MavenException, IOException
193 {
194
195 Project project = null;
196 try
197 {
198 project = new Project( projectDescriptor.toURL() );
199 }
200 catch ( Exception e )
201 {
202 throw new MavenException( "Error parsing project.xml '" + projectDescriptor.getAbsolutePath() + "'", e );
203 }
204
205
206 MavenJellyContext context =
207 MavenUtils.createContextNoDefaults( projectDescriptor.getParentFile(), parentContext );
208
209
210 String pomToExtend = project.getExtend();
211
212 if ( ( pomToExtend != null ) && useParentPom )
213 {
214
215
216
217 Expression e = JellyUtils.decomposeExpression( pomToExtend, context );
218 pomToExtend = e.evaluateAsString( context );
219 pomToExtend = MavenUtils.makeAbsolutePath( projectDescriptor.getParentFile(), pomToExtend );
220 project.setExtend( pomToExtend );
221
222 File parentPom = new File( pomToExtend );
223 parentPom = parentPom.getCanonicalFile();
224 if ( !parentPom.exists() )
225 {
226 throw new FileNotFoundException( "Parent POM not found: " + parentPom );
227 }
228
229 String parentPomPath = parentPom.getPath();
230 if ( parentPomPath.equals( projectDescriptor.getCanonicalPath() ) )
231 {
232 throw new MavenException( "Parent POM is equal to the current POM" );
233 }
234
235 Project parent = (Project) parentPoms.get( parentPomPath );
236 if ( parent == null )
237 {
238 parent = getNonJellyProject( parentPom, parentContext, true );
239 parent.setFile( parentPom );
240 parentPoms.put( parentPom.getCanonicalPath(), parent );
241 context.setParent( parent.getContext() );
242 }
243
244
245 integrateMapInContext( parent.getContext().getVariables(), context );
246
247 project.mergeParent( parent );
248 }
249
250 project.resolveIds();
251
252 applyDefaults( context );
253
254
255
256 project.setContext( context );
257 context.setProject( project );
258
259 return project;
260 }
261
262 /**
263 * This is currently used for the reactor but may be generally useful.
264 *
265 * @param directory
266 * the directory to scan for maven projects
267 * @param includes
268 * the pattern that matches a project that you want included
269 * @param excludes
270 * the pattern that matches a project that you don't want included
271 * @return a {link List} of {@link Project}s
272 * @throws MavenException
273 * when anything goes wrong.
274 */
275 public static List getProjects( File directory, String includes, String excludes ) throws MavenException
276 {
277 return getProjects( directory, includes, excludes, null );
278 }
279
280 /**
281 * This is currently used for the reactor but may be generally useful.
282 *
283 * @param directory
284 * the directory to scan for maven projects
285 * @param includes
286 * Patterns to include.
287 * @param excludes
288 * Patterns to exclude.
289 * @param context
290 * the parent context
291 * @return a {link List} of {@link Project}s
292 * @throws MavenException
293 * when anything goes wrong.
294 */
295 public static List getProjects( File directory, String includes, String excludes, MavenJellyContext context )
296 throws MavenException
297 {
298 String[] files = getFiles( directory, includes, excludes );
299
300 List projects = new ArrayList();
301
302 for ( int i = 0; i < files.length; i++ )
303 {
304 Project p = getProject( new File( files[i] ), context );
305 projects.add( p );
306 }
307
308 return projects;
309 }
310
311 /**
312 * Take the POM and interpolate the value of the project's context to create a new version of the POM with expanded
313 * context values.
314 *
315 * @param project
316 * the maven POM
317 * @return Jelly interpolated project.
318 * @throws Exception
319 * when there are errors reading FIXME
320 */
321 public static Project getJellyProject( Project project ) throws Exception
322 {
323
324 MavenJellyContext originalContext = project.getContext();
325
326
327
328
329
330 JellyContext context = new JellyContext();
331 JellyUtils.populateVariables( context, originalContext );
332
333
334
335 project.setContext( null );
336 Project parent = project.getParent();
337 project.setParent( null );
338
339
340 project = getInterpolatedPOM( project, context );
341
342
343 project.setParent( parent );
344 project.setContext( originalContext );
345 project.getContext().setProject( project );
346
347 return project;
348 }
349
350 /**
351 * Get the POM with all variables resolved.
352 *
353 * @param project
354 * the project to resolve
355 * @param context
356 * the context to retrieve variables from
357 * @return a project with no unresolved elements.
358 * @throws Exception
359 * if there is an error parsing the project FIXME
360 */
361 private static Project getInterpolatedPOM( Project project, JellyContext context ) throws Exception
362 {
363 String projectString = project.getProjectAsString();
364 Expression e = JellyUtils.decomposeExpression( projectString, context );
365 String newProjectString = e.evaluateAsString( context );
366
367
368 project = new Project( new StringReader( newProjectString ) );
369 return project;
370 }
371
372 /**
373 * Get a set of files from a specifed directory with a set of includes.
374 *
375 * @param directory
376 * Directory to scan.
377 * @param includes
378 * Comma separated list of includes.
379 * @return files
380 */
381 public static String[] getFiles( File directory, String includes )
382 {
383 return getFiles( directory, includes, null );
384 }
385
386 /**
387 * Get a set of files from a specifed directory with a set of includes.
388 *
389 * @param directory
390 * Directory to scan.
391 * @param includes
392 * Comma separated list of includes.
393 * @param excludes
394 * Comma separated list of excludes.
395 * @return files
396 */
397 public static String[] getFiles( File directory, String includes, String excludes )
398 {
399 String[] includePatterns = null;
400 if ( includes != null )
401 {
402 includePatterns = StringUtils.split( includes, "," );
403 }
404
405 String[] excludePatterns = null;
406 if ( excludes != null )
407 {
408 excludePatterns = StringUtils.split( excludes, "," );
409 }
410
411 DirectoryScanner directoryScanner = new DirectoryScanner();
412 directoryScanner.setBasedir( directory );
413 directoryScanner.setIncludes( includePatterns );
414 directoryScanner.setExcludes( excludePatterns );
415 directoryScanner.scan();
416 String[] files = directoryScanner.getIncludedFiles();
417
418 for ( int i = 0; i < files.length; i++ )
419 {
420 files[i] = new File( directory, files[i] ).getAbsolutePath();
421 }
422
423 return files;
424 }
425
426 /**
427 * Take a dominant and recessive Map and merge the key:value pairs where the recessive Map may add key:value pairs
428 * to the dominant Map but may not override any existing key:value pairs.
429 *
430 * If we have two Maps, a dominant and recessive, and their respective keys are as follows:
431 *
432 * dominantMapKeys = { a, b, c, d, e, f } recessiveMapKeys = { a, b, c, x, y, z }
433 *
434 * Then the result should be the following:
435 *
436 * resultantKeys = { a, b, c, d, e, f, x, y, z }
437 *
438 * @param dominantMap
439 * Dominant Map.
440 * @param recessiveMap
441 * Recessive Map.
442 * @return The result map with combined dominant and recessive values.
443 */
444 public static Map mergeMaps( Map dominantMap, Map recessiveMap )
445 {
446 Map result = new HashMap();
447
448 if ( ( dominantMap == null ) && ( recessiveMap == null ) )
449 {
450 return null;
451 }
452
453 if ( ( dominantMap != null ) && ( recessiveMap == null ) )
454 {
455 return dominantMap;
456 }
457
458 if ( dominantMap == null )
459 {
460 return recessiveMap;
461 }
462
463
464 Set dominantMapKeys = dominantMap.keySet();
465 Set recessiveMapKeys = recessiveMap.keySet();
466
467
468
469
470 Collection contributingRecessiveKeys =
471 CollectionUtils.subtract( recessiveMapKeys,
472 CollectionUtils.intersection( dominantMapKeys, recessiveMapKeys ) );
473
474 result.putAll( dominantMap );
475
476
477
478 for ( Iterator i = contributingRecessiveKeys.iterator(); i.hasNext(); )
479 {
480 Object key = i.next();
481 result.put( key, recessiveMap.get( key ) );
482 }
483
484 return result;
485 }
486
487 /**
488 * Take a series of <code>Map</code>s and merge them where the ordering of the array from 0..n is the dominant
489 * order.
490 *
491 * @param maps
492 * An array of Maps to merge.
493 * @return Map The result Map produced after the merging process.
494 */
495 public static Map mergeMaps( Map[] maps )
496 {
497 Map result;
498
499 if ( maps.length == 0 )
500 {
501 result = null;
502 }
503 else if ( maps.length == 1 )
504 {
505 result = maps[0];
506 }
507 else
508 {
509 result = mergeMaps( maps[0], maps[1] );
510
511 for ( int i = 2; i < maps.length; i++ )
512 {
513 result = mergeMaps( result, maps[i] );
514 }
515 }
516
517 return result;
518 }
519
520 /**
521 * Load the build.properties file for a project.
522 *
523 * @param directory
524 * the directory of the project
525 * @return the properties
526 */
527 private static Properties loadProjectBuildProperties( File directory )
528 {
529
530 File projectBuildPropertiesFile = new File( directory, "build.properties" );
531
532 LOGGER.debug( "Using projectBuildPropertiesFile: " + projectBuildPropertiesFile.getAbsolutePath() );
533 return loadProperties( projectBuildPropertiesFile );
534 }
535
536 /**
537 * Load the project.properties file for a project.
538 *
539 * @param directory
540 * the directory of the project
541 * @return the properties
542 */
543 private static Properties loadProjectProperties( File directory )
544 {
545
546 File projectPropertiesFile = new File( directory, "project.properties" );
547
548 LOGGER.debug( "Using projectPropertiesFile: " + projectPropertiesFile.getAbsolutePath() );
549 return loadProperties( projectPropertiesFile );
550 }
551
552 /**
553 * Create a jelly context given a descriptor directory.
554 *
555 * @param descriptorDirectory
556 * The directory from which to pull the standard maven properties files from.
557 * @return The generated maven based on the contents of the standard maven properties files.
558 */
559 public static MavenJellyContext createContext( File descriptorDirectory )
560 {
561 return createContext( descriptorDirectory, null );
562 }
563
564 /**
565 * Create a jelly context given a descriptor directory and parent jelly context.
566 *
567 * @param descriptorDirectory
568 * The directory from which to pull the standard maven properties files from.
569 * @param parentContext
570 * The parent jelly context.
571 * @todo should premerge driver, etc if they are being kept
572 * @return The generated maven based on the contents of the standard maven properties files.
573 */
574 public static MavenJellyContext createContext( File descriptorDirectory, MavenJellyContext parentContext )
575 {
576 MavenJellyContext context = createContextNoDefaults( descriptorDirectory, parentContext );
577 applyDefaults( context );
578 return context;
579 }
580
581 /**
582 * Create a jelly context given a descriptor directory and parent jelly context, but don't apply any defaults.
583 *
584 * @param descriptorDirectory
585 * The directory from which to pull the standard maven properties files from.
586 * @param parentContext
587 * The parent jelly context.
588 * @todo should premerge driver, etc if they are being kept
589 * @return The generated maven based on the contents of the standard maven properties files.
590 */
591 private static MavenJellyContext createContextNoDefaults( File descriptorDirectory, MavenJellyContext parentContext )
592 {
593
594 Properties systemProperties = System.getProperties();
595
596
597 File userBuildPropertiesFile = new File( System.getProperty( "user.home" ), "build.properties" );
598
599 LOGGER.debug( "Using userBuildPropertiesFile: " + userBuildPropertiesFile.getAbsolutePath() );
600 Properties userBuildProperties = loadProperties( userBuildPropertiesFile );
601
602 Properties projectProperties = loadProjectProperties( descriptorDirectory );
603 Properties projectBuildProperties = loadProjectBuildProperties( descriptorDirectory );
604
605 Properties driverProperties =
606 loadProperties( MavenUtils.class.getResourceAsStream( MavenConstants.DRIVER_PROPERTIES ) );
607
608 Map result =
609 MavenUtils.mergeMaps( new Map[] { systemProperties, userBuildProperties, projectBuildProperties,
610 projectProperties, driverProperties } );
611
612 MavenJellyContext context;
613
614 if ( parentContext != null )
615 {
616 context = new MavenJellyContext( parentContext );
617 }
618 else
619 {
620 context = new MavenJellyContext();
621 }
622
623
624 context.setInherit( false );
625
626
627 MavenUtils.integrateMapInContext( result, context );
628
629
630 context.setInherit( true );
631
632
633 context.setVariable( "basedir", descriptorDirectory.getAbsolutePath() );
634
635 return context;
636 }
637
638 /**
639 * Apply default settings.
640 *
641 * @param context
642 * Jelly context to apply the defaults.
643 */
644 private static void applyDefaults( MavenJellyContext context )
645 {
646 Properties defaultProperties =
647 loadProperties( MavenUtils.class.getResourceAsStream( MavenConstants.DEFAULTS_PROPERTIES ) );
648
649
650 MavenUtils.integrateMapInContext( defaultProperties, context );
651
652
653 context.resolveRelativePaths( new File( System.getProperty( "user.dir" ) ) );
654 }
655
656 /**
657 * Integrate a Map of key:value pairs into a <code>MavenJellyContext</code>. The values in the Map may be
658 * <code>CompositeExpression</code>s that need to be evaluated before being placed into the context.
659 *
660 * @param map
661 * Map to integrate into the provided jelly context.
662 * @param context
663 * Jelly context to integrate the map into.
664 */
665 public static void integrateMapInContext( Map map, MavenJellyContext context )
666 {
667 if ( map == null )
668 {
669 return;
670 }
671
672 JexlExpressionFactory factory = new JexlExpressionFactory();
673
674 for ( Iterator i = map.keySet().iterator(); i.hasNext(); )
675 {
676 String key = (String) i.next();
677 Object value;
678
679
680
681 if ( context.getVariables().get( key ) == null )
682 {
683 value = map.get( key );
684
685 if ( value instanceof String )
686 {
687 try
688 {
689 String literalValue = (String) value;
690 Expression expr = CompositeExpression.parse( literalValue, factory );
691
692 if ( expr != null )
693 {
694 value = expr;
695 }
696 else
697 {
698 value = literalValue;
699 }
700 }
701 catch ( Exception e )
702 {
703
704 LOGGER.debug( "Unexpected error evaluating expression", e );
705 }
706 }
707 context.setVariable( key, value );
708 }
709 }
710 }
711
712 /**
713 * Load properties from a <code>File</code>.
714 *
715 * @param file
716 * Propertie file to load.
717 * @return The loaded Properties.
718 */
719 private static Properties loadProperties( File file )
720 {
721 FileInputStream fis = null;
722 try
723 {
724 if ( file.exists() )
725 {
726 fis = new FileInputStream( file );
727 return loadProperties( fis );
728 }
729 }
730 catch ( Exception e )
731 {
732
733 LOGGER.debug( "Unexpected error loading properties", e );
734 }
735 finally
736 {
737 if ( fis != null )
738 {
739 try
740 {
741 fis.close();
742 }
743 catch ( IOException e )
744 {
745 LOGGER.debug( "WARNING: Cannot close stream!", e );
746 }
747 fis = null;
748 }
749 }
750
751 return null;
752 }
753
754 /**
755 * Load properties from an <code>InputStream</code>.
756 *
757 * @param is
758 * InputStream from which load properties.
759 * @return The loaded Properties.
760 */
761 private static Properties loadProperties( InputStream is )
762 {
763 try
764 {
765 Properties properties = new Properties();
766 properties.load( is );
767
768 for ( Iterator i = properties.keySet().iterator(); i.hasNext(); )
769 {
770 String property = (String) i.next();
771 properties.setProperty( property, properties.getProperty( property ).trim() );
772 }
773
774 return properties;
775 }
776 catch ( IOException e )
777 {
778
779 LOGGER.debug( "Unexpected exception loading properties", e );
780 }
781 finally
782 {
783 try
784 {
785 if ( is != null )
786 {
787 is.close();
788 }
789 }
790 catch ( IOException e )
791 {
792
793 LOGGER.debug( "Unexpected exception loading properties", e );
794 }
795 }
796
797 return null;
798 }
799
800 /** Resource bundle with user messages. */
801 private static ResourceBundle messages;
802
803 /**
804 * Load MavenSession user messages from a resource bundle given the user's locale.
805 *
806 * @todo Move locale tools into their own class.
807 */
808 private static void loadMessages()
809 {
810 try
811 {
812
813 messages = ResourceBundle.getBundle( "org/apache/maven/messages/messages" );
814 }
815 catch ( MissingResourceException e )
816 {
817
818
819 messages = ResourceBundle.getBundle( "org/apache/maven/messages/messages", Locale.ENGLISH );
820 }
821 }
822
823 /**
824 * Retrieve a user message.
825 *
826 * @param messageId
827 * Id of message type to use.
828 * @return Message for the user's locale.
829 */
830 public static String getMessage( String messageId )
831 {
832 return getMessage( messageId, null );
833 }
834
835 /**
836 * Retrieve a user message.
837 *
838 * @param messageId
839 * Id of message type to use.
840 * @param variable
841 * Value to substitute for ${1} in the given message.
842 * @return Message for the user's locale.
843 */
844 public static String getMessage( String messageId, Object variable )
845 {
846 if ( messages == null )
847 {
848 try
849 {
850 loadMessages();
851 }
852 catch ( MissingResourceException mre )
853 {
854 LOGGER.error( mre );
855 return messageId + ( variable == null ? "" : " " + variable );
856 }
857 }
858
859 if ( variable == null )
860 {
861 return messages.getString( messageId );
862 }
863 else
864 {
865 return StringUtils.replace( messages.getString( messageId ), "${1}", variable.toString() );
866 }
867 }
868
869 /**
870 * Resolve directory against a base directory if it is not already absolute.
871 *
872 * @param basedir
873 * the base directory for relative paths
874 * @param dir
875 * the directory to resolve
876 * @throws IOException
877 * if canonical path fails
878 * @return the canonical path of the directory if not absolute
879 */
880 public static String makeAbsolutePath( File basedir, String dir ) throws IOException
881 {
882 File f = new File( dir );
883 if ( ( f.isAbsolute() ) )
884 {
885 return f.getCanonicalPath();
886 }
887 else
888 {
889 return new File( basedir, dir ).getCanonicalPath();
890 }
891 }
892
893 /**
894 * Convert an absolute path to a relative path if it is under a given base directory.
895 *
896 * @param basedir
897 * the base directory for relative paths
898 * @param path
899 * the directory to resolve
900 * @return the relative path
901 * @throws IOException
902 * if canonical path fails
903 */
904 public static String makeRelativePath( File basedir, String path ) throws IOException
905 {
906 String canonicalBasedir = basedir.getCanonicalPath();
907 File pathFile = new File( path );
908 if ( !pathFile.isAbsolute() )
909 {
910 LOGGER.warn( "WARNING: path is not an absolute pathname! Returning path." );
911 return path;
912 }
913 String canonicalPath = pathFile.getCanonicalPath();
914
915 if ( canonicalPath.equals( canonicalBasedir ) )
916 {
917 return ".";
918 }
919
920 if ( canonicalPath.startsWith( canonicalBasedir ) )
921 {
922 if ( canonicalPath.charAt( canonicalBasedir.length() ) == File.separatorChar )
923 {
924 canonicalPath = canonicalPath.substring( canonicalBasedir.length() + 1 );
925 }
926 else
927 {
928 canonicalPath = canonicalPath.substring( canonicalBasedir.length() );
929 }
930 }
931 else
932 {
933 LOGGER.warn( "WARNING: path does not start with basedir! Returning path." );
934 return path;
935 }
936 return canonicalPath;
937 }
938
939 /**
940 * Get a list of goals from a CSV list.
941 *
942 * @param goalCsv
943 * the goals
944 * @return the list of goal names
945 */
946 public static List getGoalListFromCsv( String goalCsv )
947 {
948 StringTokenizer tok = new StringTokenizer( goalCsv, "," );
949 List goals = new ArrayList();
950 while ( tok.hasMoreTokens() )
951 {
952 goals.add( tok.nextToken().trim() );
953 }
954 return goals;
955 }
956
957 /**
958 * Debugging function.
959 *
960 * @param classLoader
961 * the class loader
962 */
963 public static void displayClassLoaderContents( ForeheadClassLoader classLoader )
964 {
965 LOGGER.info( "ClassLoader name: " + classLoader.getName() );
966
967 URL[] urls = classLoader.getURLs();
968
969 for ( int i = 0; i < urls.length; i++ )
970 {
971 LOGGER.info( "urls[" + i + "] = " + urls[i] );
972 }
973
974 ClassLoader parent = classLoader.getParent();
975 if ( ( parent != null ) && ( parent instanceof ForeheadClassLoader ) )
976 {
977 LOGGER.info( "Displaying Parent classloader: " );
978 displayClassLoaderContents( (ForeheadClassLoader) classLoader.getParent() );
979 }
980 }
981
982
983 }