001 /*
002 * Copyright 2005-2006 Stephen J. McConnell
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.library.impl;
020
021 import java.io.File;
022 import java.util.Arrays;
023 import java.util.ArrayList;
024 import java.util.List;
025 import java.util.regex.Pattern;
026 import java.util.regex.Matcher;
027 import java.util.Properties;
028 import java.util.Hashtable;
029 import java.util.Map;
030
031 import net.dpml.library.info.Scope;
032 import net.dpml.library.info.AbstractDirective;
033 import net.dpml.library.info.ModuleDirective;
034 import net.dpml.library.info.ResourceDirective;
035 import net.dpml.library.info.DependencyDirective;
036 import net.dpml.library.info.ResourceDirective.Classifier;
037 import net.dpml.library.info.TypeDirective;
038 import net.dpml.library.info.InfoDirective;
039 import net.dpml.library.Module;
040 import net.dpml.library.Resource;
041 import net.dpml.library.ResourceNotFoundException;
042 import net.dpml.library.ModuleNotFoundException;
043
044 import net.dpml.lang.Category;
045 import net.dpml.lang.DuplicateKeyException;
046
047 /**
048 * A Module is a collection of resources. It serves to establish a
049 * namespace and a framework for sharing properties and characteristics
050 * defined within within the module with resources contained within the
051 * module.
052 *
053 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
054 * @version 1.1.2
055 */
056 public final class DefaultModule extends DefaultResource implements Module
057 {
058 private final boolean m_root;
059 private final ModuleDirective m_directive;
060 private final Map m_map = new Hashtable();
061
062 /**
063 * Constructor used by the library to create a virtual root module os shared
064 * resource references.
065 * @param logger the assigned logging channel
066 * @param library the library
067 * @param directive the directive from which common properties are established
068 */
069 DefaultModule( final DefaultLibrary library, final AbstractDirective directive )
070 {
071 super( library, directive );
072
073 m_root = true;
074 m_directive = null;
075 }
076
077 /**
078 * Creation of a new nested module.
079 * @param logger the assigned logging channel
080 * @param library the library
081 * @param module the parent module
082 * @param directive the directive from which common properties are established
083 */
084 DefaultModule(
085 final DefaultLibrary library, final DefaultModule module, final ModuleDirective directive )
086 throws DuplicateKeyException
087 {
088 super( library, module, directive );
089
090 m_root = false;
091 m_directive = directive;
092 ResourceDirective[] directives = directive.getResourceDirectives();
093 for( int i=0; i<directives.length; i++ )
094 {
095 ResourceDirective res = directives[i];
096 addResource( res );
097 }
098 }
099
100 /**
101 * Add a resource to the module.
102 * @param directive the resource directive to add to the module
103 * @throws DuplicateKeyException if a resource name is already bound
104 */
105 DefaultResource addResource( final ResourceDirective directive ) throws DuplicateKeyException
106 {
107 if( null == directive )
108 {
109 throw new NullPointerException( "directive" );
110 }
111
112 synchronized( m_map )
113 {
114 String key = directive.getName();
115 if( m_map.containsKey( key ) )
116 {
117 if( directive instanceof ModuleDirective )
118 {
119 DefaultModule module = (DefaultModule) m_map.get( key );
120
121 // check basedir values
122
123 if( null != directive.getBasedir() )
124 {
125 if( null != module.getBaseDir() )
126 {
127 File base = new File( getBaseDir(), directive.getBasedir() );
128 if( !module.getBaseDir().equals( base ) )
129 {
130 final String error =
131 "Cannot merge modules with different base directories."
132 + "\nModule: " + module
133 + "\nPrimary base: " + module.getBaseDir()
134 + "\nSecondary base: " + base;
135 throw new IllegalStateException( error );
136 }
137 }
138 }
139
140 // check versions
141
142 if( null != directive.getVersion() )
143 {
144 if( module.getVersion().equals( directive.getVersion() ) )
145 {
146 final String error =
147 "Cannot merge modules with different versions."
148 + "\nModule: " + module
149 + "\nPrimary version: " + module.getVersion()
150 + "\nSecondary version: " + directive.getVersion();
151 throw new IllegalStateException( error );
152 }
153 }
154
155 // check types
156
157 if( directive.getTypeDirectives().length > 0 )
158 {
159 final String error =
160 "Cannot merge a module with type production directives."
161 + "\nModule: " + module;
162 throw new IllegalStateException( error );
163 }
164
165 // check dependencies
166
167 if( directive.getDependencyDirectives().length > 0 )
168 {
169 final String error =
170 "Cannot merge a module with dependency directives."
171 + "\nModule: " + module;
172 throw new IllegalStateException( error );
173 }
174
175 // add additional resources
176
177 ModuleDirective d = (ModuleDirective) directive;
178 ResourceDirective[] resources = d.getResourceDirectives();
179 for( int i=0; i<resources.length; i++ )
180 {
181 ResourceDirective r = resources[i];
182 module.addResource( r );
183 }
184 return module;
185 }
186 else
187 {
188 throw new DuplicateKeyException( key );
189 }
190 }
191 else
192 {
193 DefaultLibrary library = getDefaultLibrary();
194 if( directive instanceof ModuleDirective )
195 {
196 ModuleDirective d = (ModuleDirective) directive;
197 DefaultModule module = new DefaultModule( library, this, d );
198 m_map.put( key, module );
199 return module;
200 }
201 else
202 {
203 DefaultResource resource = new DefaultResource( library, this, directive );
204 m_map.put( key, resource );
205 return resource;
206 }
207 }
208 }
209 }
210
211 //----------------------------------------------------------------------------
212 // Module
213 //----------------------------------------------------------------------------
214
215 /**
216 * Return an array of immediate resources contained within the
217 * module.
218 * @return the resource array
219 */
220 public Resource[] getResources()
221 {
222 return getDefaultResources();
223 }
224
225 /**
226 * Return a resource using a supplied name.
227 * @param ref a path relative to the module
228 * @return the resource array
229 * @exception ResourceNotFoundException if the resource does not exist
230 */
231 public Resource getResource( final String ref ) throws ResourceNotFoundException
232 {
233 try
234 {
235 return getDefaultResource( ref );
236 }
237 catch( InvalidNameException e )
238 {
239 final String error =
240 "Resource reference ["
241 + ref
242 + "] is undefined.";
243 throw new ResourceNotFoundException( error, e );
244 }
245 }
246
247 /**
248 * Return the array of modules that are direct children of this module.
249 * @return the child modules
250 */
251 public Module[] getModules()
252 {
253 return getDefaultModules();
254 }
255
256 /**
257 * Return a module using a supplied reference.
258 * @param ref a path relative to the module
259 * @return the module array
260 * @exception ModuleNotFoundException if the module does not exist
261 */
262 public Module getModule( final String ref ) throws ModuleNotFoundException
263 {
264 try
265 {
266 return getDefaultModule( ref );
267 }
268 catch( InvalidNameException e )
269 {
270 final String error =
271 "Cannot locate module ["
272 + ref
273 + "] within module ["
274 + getResourcePath()
275 + "]";
276 throw new ModuleNotFoundException( error, e );
277 }
278 }
279
280 /**
281 * Return the array of modules that are descendants of this module.
282 * @return the descendants module array
283 */
284 public Module[] getAllModules()
285 {
286 return getAllDefaultModules();
287 }
288
289 /**
290 * <p>Select a set of resource matching a supplied a resource selection
291 * constraint. The constraint may contain the wildcards '**' and '*'.
292 * @param criteria the selection criteria
293 * @param local if true limit the selection to local projects
294 * @param sort if true the returned array will be sorted relative to dependencies
295 * otherwise the array will be sorted alphanumerically
296 * @return an array of resources matching the selection criteria
297 */
298 public Resource[] select( final String criteria, final boolean local, final boolean sort )
299 {
300 DefaultResource[] resources = selectDefaultResources( local, criteria );
301 if( sort )
302 {
303 return sortDefaultResources( resources, Scope.TEST );
304 }
305 else
306 {
307 Arrays.sort( resources );
308 return resources;
309 }
310
311 }
312
313 /**
314 * Locate a resource relative to a base directory.
315 * @param base the base directory
316 * @return a resource with a matching basedir
317 * @exception ResourceNotFoundException if resource match relative to the supplied base
318 */
319 public Resource locate( final File base ) throws ResourceNotFoundException
320 {
321 DefaultResource[] resources = selectDefaultResources( true, "**/*" );
322 for( int i=0; i<resources.length; i++ )
323 {
324 DefaultResource resource = resources[i];
325 File basedir = resource.getBaseDir();
326 if( ( null != basedir ) && base.equals( basedir ) )
327 {
328 return resource;
329 }
330 }
331 throw new ResourceNotFoundException( base.toString() );
332 }
333
334 /**
335 * Return a directive suitable for publication as an external description.
336 * @return the resource directive
337 */
338 public ModuleDirective export()
339 {
340 if( null == m_directive )
341 {
342 final String error =
343 "Cannot export from the virtual root.";
344 throw new UnsupportedOperationException( error );
345 }
346
347 DefaultModule parent = getDefaultParent();
348 if( null == parent )
349 {
350 //
351 // exporting a top-level module
352 //
353
354 return (ModuleDirective) exportResource( this );
355 }
356 else
357 {
358 //
359 // exporting the nested module
360 //
361
362 String path = getResourcePath();
363 return exportModule( this, path );
364 }
365 }
366
367 /**
368 * Return a directive suitable for publication as an external description.
369 * @param module the enclosing module
370 * @return the resource directive
371 * @exception IllegalArgumentException if the module is not a top-level module
372 */
373 ResourceDirective exportResource( final DefaultModule module ) throws IllegalArgumentException
374 {
375 String name = getName();
376 return exportModule( module, name );
377 }
378
379 /**
380 * Return a directive suitable for publication as an external description.
381 * @param module the enclosing module
382 * @return the resource directive
383 * @exception IllegalArgumentException if the module is not a top-level module
384 */
385 ModuleDirective exportModule( final DefaultModule module, final String name ) throws IllegalArgumentException
386 {
387 DefaultResource[] resources = getDefaultResources();
388 ResourceDirective[] directives = new ResourceDirective[ resources.length ];
389 for( int i=0; i<directives.length; i++ )
390 {
391 DefaultResource resource = resources[i];
392 directives[i] = resource.exportResource( module );
393 }
394 String version = getVersion();
395 String basedir = null;
396 InfoDirective info = m_directive.getInfoDirective();
397 TypeDirective[] types = m_directive.getTypeDirectives();
398 TypeDirective[] exportedTypes = createExportedTypes( types );
399 Properties properties = getExportProperties();
400 return new ModuleDirective(
401 name, version, Classifier.EXTERNAL, basedir,
402 info, exportedTypes, new DependencyDirective[0],
403 directives, properties, null );
404 }
405
406 //----------------------------------------------------------------------------
407 // Object
408 //----------------------------------------------------------------------------
409
410 /**
411 * Return the string representation of the module.
412 * @return the string value
413 */
414 public String toString()
415 {
416 return toString( "module" );
417 }
418
419 //----------------------------------------------------------------------------
420 // DefaultResource (overriding)
421 //----------------------------------------------------------------------------
422
423 DefaultResource[] getLocalDefaultProviders( final Scope scope, final Category category )
424 {
425 DefaultResource[] local = super.getLocalDefaultProviders( scope, category );
426 if( Scope.BUILD.equals( scope ) )
427 {
428 ArrayList stack = new ArrayList();
429 for( int i=0; i<local.length; i++ )
430 {
431 DefaultResource resource = local[i];
432 stack.add( resource );
433 }
434 return expandLocalDefaultProviders( stack );
435 }
436 else if( Scope.RUNTIME.equals( scope ) )
437 {
438 ArrayList stack = new ArrayList();
439 for( int i=0; i<local.length; i++ )
440 {
441 DefaultResource resource = local[i];
442 stack.add( resource );
443 }
444
445 DefaultResource[] resources = getDefaultResources();
446 for( int i=0; i<resources.length; i++ )
447 {
448 DefaultResource resource = resources[i];
449 if( !stack.contains( resource ) )
450 {
451 stack.add( resource );
452 }
453 }
454 return (DefaultResource[]) stack.toArray( new DefaultResource[0] );
455 }
456 else
457 {
458 return local;
459 }
460 }
461
462 DefaultResource[] expandLocalDefaultProviders( final List stack )
463 {
464 DefaultResource[] resources = getDefaultResources();
465 for( int i=0; i<resources.length; i++ )
466 {
467 DefaultResource resource = resources[i];
468 if( resource instanceof DefaultModule )
469 {
470 DefaultModule module = (DefaultModule) resource;
471 String path = module.getResourcePath();
472 if( !path.startsWith( getResourcePath() ) )
473 //if( !getResourcePath().startsWith( path ) )
474 {
475 DefaultResource[] providers = module.expandLocalDefaultProviders( stack );
476 for( int j=0; j<providers.length; j++ )
477 {
478 DefaultResource r = providers[j];
479 if( !stack.contains( r ) )
480 {
481 stack.add( r );
482 }
483 }
484 }
485 }
486 else
487 {
488 DefaultResource[] providers =
489 resource.getAggregatedDefaultProviders( Scope.TEST, true, false );
490 getParentModules( stack, providers );
491 }
492 }
493 return (DefaultResource[]) stack.toArray( new DefaultResource[0] );
494 }
495
496 private void getParentModules( final List stack, final DefaultResource[] resources )
497 {
498 for( int i=0; i<resources.length; i++ )
499 {
500 DefaultResource resource = resources[i];
501 if( !resource.isAnonymous() )
502 {
503 DefaultModule parent = resource.getDefaultParent();
504 if( null != parent )
505 {
506 String path = parent.getResourcePath();
507 if( !path.startsWith( getResourcePath() ) && !stack.contains( parent ) )
508 {
509 stack.add( parent );
510 }
511 }
512 }
513 }
514 }
515
516 void sortDefaultResource(
517 final List visited, final List stack, final Scope scope, final DefaultResource[] resources )
518 {
519 if( visited.contains( this ) )
520 {
521 return;
522 }
523
524 visited.add( this );
525 DefaultResource[] providers =
526 getAggregatedDefaultProviders( scope, false, false );
527 for( int i=0; i<providers.length; i++ )
528 {
529 DefaultResource provider = providers[i];
530 if( isaMember( resources, provider ) )
531 {
532 provider.sortDefaultResource( visited, stack, scope, resources );
533 }
534 }
535
536 DefaultModule[] modules = getProviderModules( scope );
537 for( int i=0; i<modules.length; i++ )
538 {
539 DefaultResource module = modules[i];
540 if( isaMember( resources, module ) )
541 {
542 module.sortDefaultResource( visited, stack, scope, resources );
543 }
544 }
545
546 if( !stack.contains( this ) )
547 {
548 stack.add( this );
549 }
550 }
551
552 //----------------------------------------------------------------------------
553 // root semantics
554 //----------------------------------------------------------------------------
555
556 boolean isRoot()
557 {
558 return m_root;
559 }
560
561 //----------------------------------------------------------------------------
562 // resource and module lookup
563 //----------------------------------------------------------------------------
564
565 DefaultResource[] getDefaultResources()
566 {
567 return (DefaultResource[]) m_map.values().toArray( new DefaultResource[0] );
568 }
569
570 DefaultResource getDefaultResource( final String ref )
571 {
572 if( null == ref )
573 {
574 throw new NullPointerException( "ref" );
575 }
576 int n = ref.indexOf( "/" );
577 if( n > 0 )
578 {
579 String pre = ref.substring( 0, n );
580 String post = ref.substring( n+1 );
581 DefaultModule module = getDefaultModule( pre );
582 return module.getDefaultResource( post );
583 }
584 else
585 {
586 DefaultResource[] resources = getDefaultResources();
587 for( int i=0; i<resources.length; i++ )
588 {
589 DefaultResource resource = resources[i];
590 if( ref.equals( resource.getName() ) )
591 {
592 return resource;
593 }
594 }
595 final String error =
596 "The reference to ["
597 + ref
598 + "] within the module ["
599 + getResourcePath()
600 + "] could not be resolved.";
601 throw new InvalidNameException( error );
602 }
603 }
604
605 DefaultModule getDefaultModule( final String ref )
606 {
607 if( null == ref )
608 {
609 throw new NullPointerException( "ref" );
610 }
611 int n = ref.indexOf( "/" );
612 if( n == 0 )
613 {
614 String newRef = ref.substring( 1 );
615 return getDefaultModule( newRef );
616 }
617 else if( n > 0 )
618 {
619 String pre = ref.substring( 0, n );
620 String post = ref.substring( n+1 );
621 DefaultModule module = getDefaultModule( pre );
622 return module.getDefaultModule( post );
623 }
624 else
625 {
626 DefaultResource resource = null;
627 try
628 {
629 resource = getDefaultResource( ref );
630 }
631 catch( InvalidNameException e )
632 {
633 final String error =
634 "The reference to module ["
635 + ref
636 + "] within the module ["
637 + getResourcePath()
638 + "] does not exist.";
639 throw new InvalidNameException( error, e );
640 }
641 if( resource instanceof DefaultModule )
642 {
643 return (DefaultModule) resource;
644 }
645 else
646 {
647 final String error =
648 "A reference to module ["
649 + ref
650 + "] within the module ["
651 + getResourcePath()
652 + "] returned a reference to a non-module resource.";
653 throw new InvalidNameException( error );
654 }
655 }
656 }
657
658 DefaultModule[] getDefaultModules()
659 {
660 ArrayList stack = new ArrayList();
661 DefaultResource[] resources = getDefaultResources();
662 for( int i=0; i<resources.length; i++ )
663 {
664 DefaultResource resource = resources[i];
665 if( resource instanceof DefaultModule )
666 {
667 stack.add( resource );
668 }
669 }
670 return (DefaultModule[]) stack.toArray( new DefaultModule[0] );
671 }
672
673 DefaultModule[] getAllDefaultModules()
674 {
675 return getAllDefaultModules( true, false );
676 }
677
678 DefaultModule[] getAllDefaultModules( final boolean sort, final boolean self )
679 {
680 if( sort )
681 {
682 DefaultModule[] modules = getAllDefaultModules( false, self );
683 return sortDefaultModules( modules );
684 }
685 else
686 {
687 DefaultModule[] modules = getDefaultModules();
688 ArrayList visited = new ArrayList();
689 ArrayList stack = new ArrayList();
690 for( int i=0; i<modules.length; i++ )
691 {
692 DefaultModule module = modules[i];
693 collectChildModules( visited, stack, module );
694 }
695 if( self )
696 {
697 stack.add( this );
698 }
699 return (DefaultModule[]) stack.toArray( new DefaultModule[0] );
700 }
701 }
702
703 private void collectChildModules(
704 final List visited, final List stack, final DefaultModule module )
705 {
706 if( visited.contains( module ) )
707 {
708 return;
709 }
710 visited.add( module );
711 DefaultModule[] children = module.getDefaultModules();
712 for( int i=0; i<children.length; i++ )
713 {
714 collectChildModules( visited, stack, children[i] );
715 }
716 stack.add( module );
717 }
718
719 //----------------------------------------------------------------------------
720 // Selection logic
721 //----------------------------------------------------------------------------
722
723 DefaultResource[] selectDefaultResources( final String spec )
724 {
725 return selectDefaultResources( false, spec );
726 }
727
728 DefaultResource[] selectDefaultResources( final boolean local, final String spec )
729 {
730 DefaultResource[] resources = doSelectDefaultResources( false, spec );
731 if( local )
732 {
733 return filterProjects( resources );
734 }
735 else
736 {
737 return resources;
738 }
739 }
740
741 DefaultResource[] doSelectDefaultResources( final boolean wild, final String spec )
742 {
743 String[] tokens = spec.split( "/" );
744 if( tokens.length == 0 )
745 {
746 return new DefaultResource[0];
747 }
748 else if( tokens.length == 1 )
749 {
750 String token = tokens[0];
751 if( "**".equals( token ) )
752 {
753 return getAllDefaultModules( true, !m_root );
754 }
755 else if( "*".equals( token ) )
756 {
757 if( wild && !m_root )
758 {
759 DefaultResource[] resources = getDefaultResources();
760 DefaultResource[] result = new DefaultResource[ resources.length + 1 ];
761 System.arraycopy( resources, 0, result, 0, resources.length );
762 result[ resources.length ] = this;
763 return result;
764 }
765 else
766 {
767 return getDefaultResources();
768 }
769 }
770 else
771 {
772 Pattern pattern = createSelectionPattern( token );
773 DefaultResource[] resources = getDefaultResources();
774 DefaultResource[] selection = selectUsingPattern( resources, pattern );
775 return selection;
776 }
777 }
778 else
779 {
780 String token = tokens[0];
781 boolean wildcard = ( token.indexOf( "**" ) > -1 );
782 String remainder = getRemainderOfSelection( spec, "/", token );
783 DefaultModule[] modules = selectDefaultModules( token );
784 ArrayList list = new ArrayList();
785 for( int i=0; i<modules.length; i++ )
786 {
787 DefaultModule module = modules[i];
788 DefaultResource[] selection = module.doSelectDefaultResources( wildcard, remainder );
789 aggregate( list, selection );
790 }
791 if( wildcard )
792 {
793 DefaultResource[] selection = doSelectDefaultResources( wildcard, remainder );
794 aggregate( list, selection );
795 }
796 return (DefaultResource[]) list.toArray( new DefaultResource[0] );
797 }
798 }
799
800 DefaultModule[] selectDefaultModules( final String token )
801 {
802 if( "**".equals( token ) )
803 {
804 return getAllDefaultModules( true, !m_root );
805 }
806 else if( "*".equals( token ) )
807 {
808 return getDefaultModules();
809 }
810 else
811 {
812 Pattern pattern = createSelectionPattern( token );
813 DefaultModule[] modules = getDefaultModules();
814 DefaultResource[] selection = selectUsingPattern( modules, pattern );
815 DefaultModule[] result = new DefaultModule[ selection.length ];
816 for( int i=0; i<selection.length; i++ )
817 {
818 result[i] = (DefaultModule) selection[i];
819 }
820 return result;
821 }
822 }
823
824 private DefaultResource[] selectUsingPattern( final DefaultResource[] resources, final Pattern pattern )
825 {
826 ArrayList list = new ArrayList();
827 for( int i=0; i<resources.length; i++ )
828 {
829 Resource resource = resources[i];
830 String name = resource.getName();
831 Matcher matcher = pattern.matcher( name );
832 boolean matches = matcher.matches();
833 if( matches )
834 {
835 list.add( resource );
836 }
837 }
838 return (DefaultResource[]) list.toArray( new DefaultResource[0] );
839 }
840
841 private String getRemainderOfSelection( final String spec, final String delimiter, final String token )
842 {
843 int n = token.length() + delimiter.length();
844 return spec.substring( n );
845 }
846
847 private void aggregate( final List list, final DefaultResource[] resources )
848 {
849 for( int i=0; i<resources.length; i++ )
850 {
851 DefaultResource resource = resources[i];
852 if( !list.contains( resource ) )
853 {
854 list.add( resources[i] );
855 }
856 }
857 }
858
859 private Pattern createSelectionPattern( final String token )
860 {
861 StringBuffer buffer = new StringBuffer();
862 boolean wildcard = ( token.indexOf( "*" ) > -1 );
863 if( wildcard )
864 {
865 String[] blocks = token.split( "\\*", -1 );
866 buffer.append( "(" );
867 for( int j=0; j<blocks.length; j++ )
868 {
869 buffer.append( "\\Q" );
870 buffer.append( blocks[j] );
871 buffer.append( "\\E" );
872 if( j < ( blocks.length-1 ) )
873 {
874 buffer.append( ".*" );
875 }
876 }
877 buffer.append( ")" );
878 }
879 else
880 {
881 buffer.append( "(\\Q" );
882 buffer.append( token );
883 buffer.append( "\\E)" );
884 }
885 String expression = buffer.toString();
886 return Pattern.compile( expression );
887 }
888
889 //----------------------------------------------------------------------------
890 // Module sorting
891 //----------------------------------------------------------------------------
892
893 private DefaultModule[] sortDefaultModules( final DefaultModule[] modules )
894 {
895 Scope scope = Scope.TEST;
896 ArrayList visited = new ArrayList();
897 ArrayList stack = new ArrayList();
898 for( int i=0; i<modules.length; i++ )
899 {
900 DefaultModule module = modules[i];
901 module.sortDefaultResource( visited, stack, scope, modules );
902 }
903 return (DefaultModule[]) stack.toArray( new DefaultModule[0] );
904 }
905
906 /**
907 * Returns a sorted array of the provider modules this this module depends on.
908 * The notion of dependency is ressolved via (a) direct depedencies declared
909 * by the module, (b) subsidiary module which are considered as sippliers to
910 * this module, and (c) module referenced by any resources contained within
911 * this or any subsidiary module.
912 */
913 private DefaultModule[] getProviderModules( final Scope scope )
914 {
915 ArrayList visited = new ArrayList();
916 ArrayList stack = new ArrayList();
917 processModuleDependencies( visited, stack, scope, this );
918 return (DefaultModule[]) stack.toArray( new DefaultModule[0] );
919 }
920
921 private void processModuleDependencies(
922 final List visited, final List stack, final Scope scope, final DefaultResource resource )
923 {
924 if( visited.contains( resource ) )
925 {
926 return;
927 }
928
929 visited.add( resource );
930 final boolean expansion = false;
931 final boolean filtering = false;
932
933 Classifier classifier = resource.getClassifier();
934 if( classifier.equals( Classifier.ANONYMOUS ) )
935 {
936 return;
937 }
938
939 if( resource instanceof DefaultModule )
940 {
941 DefaultModule module = (DefaultModule) resource;
942 DefaultResource[] providers = module.getAggregatedDefaultProviders( scope, expansion, filtering );
943 for( int i=0; i<providers.length; i++ )
944 {
945 processModuleDependencies( visited, stack, scope, providers[i] );
946 }
947 DefaultResource[] children = module.getDefaultModules();
948 for( int i=0; i<children.length; i++ )
949 {
950 processModuleDependencies( visited, stack, scope, children[i] );
951 }
952 if( !resource.equals( this ) )
953 {
954 stack.add( module );
955 }
956 }
957 else
958 {
959 DefaultResource[] resources =
960 resource.getAggregatedDefaultProviders( scope, expansion, filtering );
961 for( int i=0; i<resources.length; i++ )
962 {
963 DefaultModule m = resources[i].getDefaultParent();
964 processModuleDependencies( visited, stack, scope, m );
965 }
966 }
967 }
968
969 private DefaultResource[] filterProjects( final DefaultResource[] resources )
970 {
971 ArrayList list = new ArrayList();
972 for( int i=0; i<resources.length; i++ )
973 {
974 DefaultResource resource = resources[i];
975 if( resource.isLocal() )
976 {
977 list.add( resource );
978 }
979 }
980 return (DefaultResource[]) list.toArray( new DefaultResource[0] );
981 }
982 }