View Javadoc

1   package org.apache.maven.project;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Enumeration;
24  import java.util.Iterator;
25  import java.util.LinkedHashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Properties;
29  import java.util.TreeMap;
30  
31  import org.apache.maven.model.Activation;
32  import org.apache.maven.model.ActivationFile;
33  import org.apache.maven.model.ActivationOS;
34  import org.apache.maven.model.ActivationProperty;
35  import org.apache.maven.model.Build;
36  import org.apache.maven.model.BuildBase;
37  import org.apache.maven.model.CiManagement;
38  import org.apache.maven.model.Contributor;
39  import org.apache.maven.model.Dependency;
40  import org.apache.maven.model.DependencyManagement;
41  import org.apache.maven.model.DeploymentRepository;
42  import org.apache.maven.model.Developer;
43  import org.apache.maven.model.DistributionManagement;
44  import org.apache.maven.model.Exclusion;
45  import org.apache.maven.model.Extension;
46  import org.apache.maven.model.IssueManagement;
47  import org.apache.maven.model.License;
48  import org.apache.maven.model.MailingList;
49  import org.apache.maven.model.Model;
50  import org.apache.maven.model.ModelBase;
51  import org.apache.maven.model.Notifier;
52  import org.apache.maven.model.Organization;
53  import org.apache.maven.model.Parent;
54  import org.apache.maven.model.Plugin;
55  import org.apache.maven.model.PluginContainer;
56  import org.apache.maven.model.PluginExecution;
57  import org.apache.maven.model.PluginManagement;
58  import org.apache.maven.model.Prerequisites;
59  import org.apache.maven.model.Profile;
60  import org.apache.maven.model.Relocation;
61  import org.apache.maven.model.ReportPlugin;
62  import org.apache.maven.model.ReportSet;
63  import org.apache.maven.model.Reporting;
64  import org.apache.maven.model.Repository;
65  import org.apache.maven.model.RepositoryBase;
66  import org.apache.maven.model.RepositoryPolicy;
67  import org.apache.maven.model.Resource;
68  import org.apache.maven.model.Scm;
69  import org.apache.maven.model.Site;
70  import org.codehaus.plexus.util.xml.Xpp3Dom;
71  
72  public final class ModelUtils
73  {
74  
75      private static final ModelPartCloner DEPENDENCY_CLONER = new ModelPartCloner()
76      {
77          public Object cloneModelPart( Object src )
78          {
79              return ModelUtils.cloneDependency( (Dependency) src );
80          }
81      };
82  
83      private static final ModelPartCloner PLUGIN_CLONER = new ModelPartCloner()
84      {
85          public Object cloneModelPart( Object src )
86          {
87              return ModelUtils.clonePlugin( (Plugin) src );
88          }
89      };
90  
91      private static final ModelPartCloner EXTENSION_CLONER = new ModelPartCloner()
92      {
93          public Object cloneModelPart( Object src )
94          {
95              return ModelUtils.cloneExtension( (Extension) src );
96          }
97      };
98  
99      private static final ModelPartCloner RESOURCE_CLONER = new ModelPartCloner()
100     {
101         public Object cloneModelPart( Object src )
102         {
103             return ModelUtils.cloneResource( (Resource) src );
104         }
105     };
106 
107     private static final ModelPartCloner NOTIFIER_CLONER = new ModelPartCloner()
108     {
109         public Object cloneModelPart( Object src )
110         {
111             return ModelUtils.cloneNotifier( (Notifier) src );
112         }
113     };
114 
115     private static final ModelPartCloner CONTRIBUTOR_CLONER = new ModelPartCloner()
116     {
117         public Object cloneModelPart( Object src )
118         {
119             return ModelUtils.cloneContributor( (Contributor) src );
120         }
121     };
122 
123     private static final ModelPartCloner DEVELOPER_CLONER = new ModelPartCloner()
124     {
125         public Object cloneModelPart( Object src )
126         {
127             return ModelUtils.cloneDeveloper( (Developer) src );
128         }
129     };
130 
131     private static final ModelPartCloner LICENSE_CLONER = new ModelPartCloner()
132     {
133         public Object cloneModelPart( Object src )
134         {
135             return ModelUtils.cloneLicense( (License) src );
136         }
137     };
138 
139     private static final ModelPartCloner MAILING_LIST_CLONER = new ModelPartCloner()
140     {
141         public Object cloneModelPart( Object src )
142         {
143             return ModelUtils.cloneMailingList( (MailingList) src );
144         }
145     };
146 
147     private static final ModelPartCloner REPOSITORY_CLONER = new ModelPartCloner()
148     {
149         public Object cloneModelPart( Object src )
150         {
151             return ModelUtils.cloneRepository( (Repository) src );
152         }
153     };
154 
155     private static final ModelPartCloner PROFILE_CLONER = new ModelPartCloner()
156     {
157         public Object cloneModelPart( Object src )
158         {
159             return ModelUtils.cloneProfile( (Profile) src );
160         }
161     };
162 
163     private static final ModelPartCloner REPORT_PLUGIN_CLONER = new ModelPartCloner()
164     {
165         public Object cloneModelPart( Object src )
166         {
167             return ModelUtils.cloneReportPlugin( (ReportPlugin) src );
168         }
169     };
170 
171     private static final ModelPartCloner REPORT_SET_CLONER = new ModelPartCloner()
172     {
173         public Object cloneModelPart( Object src )
174         {
175             return ModelUtils.cloneReportSet( (ReportSet) src );
176         }
177     };
178 
179     private static final ModelPartCloner DEPENDENCY_EXCLUSION_CLONER = new ModelPartCloner()
180     {
181         public Object cloneModelPart( Object src )
182         {
183             return ModelUtils.cloneExclusion( (Exclusion) src );
184         }
185     };
186 
187     private static final ModelPartCloner PLUGIN_EXECUTION_CLONER = new ModelPartCloner()
188     {
189         public Object cloneModelPart( Object src )
190         {
191             return ModelUtils.clonePluginExecution( (PluginExecution) src );
192         }
193     };
194 
195     /**
196      * Given this plugin list:
197      *
198      * A1 -> B -> C -> A2 -> D
199      *
200      * Rearrange it to this:
201      *
202      * A(A1 + A2) -> B -> C -> D
203      *
204      * In cases of overlapping definitions, A1 is overridden by A2
205      *
206      */
207     public static void mergeDuplicatePluginDefinitions( PluginContainer pluginContainer )
208     {
209         if ( pluginContainer == null )
210         {
211             return;
212         }
213 
214         List originalPlugins = pluginContainer.getPlugins();
215 
216         if ( ( originalPlugins == null ) || originalPlugins.isEmpty() )
217         {
218             return;
219         }
220 
221         List normalized = new ArrayList( originalPlugins.size() );
222 
223         for ( Iterator it = originalPlugins.iterator(); it.hasNext(); )
224         {
225             Plugin currentPlugin = (Plugin) it.next();
226 
227             if ( normalized.contains( currentPlugin ) )
228             {
229                 int idx = normalized.indexOf( currentPlugin );
230                 Plugin firstPlugin = (Plugin) normalized.get( idx );
231 
232                 // MNG-3719: merge currentPlugin with firstPlugin as parent,
233                 // then use updated currentPlugin as new parent
234                 mergePluginDefinitions( currentPlugin, firstPlugin, false );
235                 normalized.set(idx, currentPlugin);
236             }
237             else
238             {
239                 normalized.add( currentPlugin );
240             }
241         }
242 
243         pluginContainer.setPlugins( normalized );
244     }
245 
246     public static ReportSet cloneReportSet( ReportSet src )
247     {
248         if ( src == null )
249         {
250             return null;
251         }
252         
253         ReportSet result = new ReportSet();
254         
255         result.setConfiguration( cloneConfiguration( src.getConfiguration() ) );
256         result.setId( src.getId() );
257         result.setInherited( src.getInherited() );
258         result.setReports( cloneListOfStrings( src.getReports() ) );
259         
260         return result;
261     }
262 
263     public static ReportPlugin cloneReportPlugin( ReportPlugin src )
264     {
265         if ( src == null )
266         {
267             return null;
268         }
269         
270         ReportPlugin result = new ReportPlugin();
271         
272         result.setArtifactId( src.getArtifactId() );
273         result.setConfiguration( cloneConfiguration( src.getConfiguration() ) );
274         result.setGroupId( src.getGroupId() );
275         result.setInherited( src.getInherited() );
276         result.setReportSets( cloneList( src.getReportSets(), REPORT_SET_CLONER ) );
277         result.setVersion( src.getVersion() );
278         
279         return result;
280     }
281 
282     public static Profile cloneProfile( Profile src )
283     {
284         if ( src == null )
285         {
286             return null;
287         }
288         
289         Profile result = new Profile();
290         
291         cloneModelBaseFields( src, result );
292         
293         result.setActivation( cloneActivation( src.getActivation() ) );
294         
295         BuildBase resultBuild = null;
296         if ( src.getBuild() != null )
297         {
298             resultBuild = new BuildBase();
299             cloneBuildBaseFields( src.getBuild(), resultBuild );
300         }
301         result.setBuild( resultBuild );
302         
303         result.setId( src.getId() );
304         result.setSource( src.getSource() );
305         
306         return result;
307     }
308 
309     private static void cloneModelBaseFields( ModelBase src, ModelBase result )
310     {
311         result.setDependencies( cloneList( src.getDependencies(), DEPENDENCY_CLONER ) );
312         result.setDependencyManagement( cloneDependencyManagement( src.getDependencyManagement() ) );
313         result.setDistributionManagement( cloneDistributionManagement( src.getDistributionManagement() ) );
314         
315         result.setModules( cloneListOfStrings( src.getModules() ) );
316 
317         result.setPluginRepositories( cloneList( src.getPluginRepositories(), REPOSITORY_CLONER ) );
318         result.setProperties( cloneProperties( src.getProperties() ) );
319         result.setReporting( cloneReporting( src.getReporting() ) );
320         result.setRepositories( cloneList( src.getRepositories(), REPOSITORY_CLONER ) );
321     }
322 
323     public static Reporting cloneReporting( Reporting src )
324     {
325         if ( src == null )
326         {
327             return null;
328         }
329         
330         Reporting result = new Reporting();
331         
332         result.setExcludeDefaults( src.isExcludeDefaults() );
333         result.setOutputDirectory( src.getOutputDirectory() );
334         result.setPlugins( cloneList( src.getPlugins(), REPORT_PLUGIN_CLONER ) );
335         
336         return result;
337     }
338 
339     public static Activation cloneActivation( Activation src )
340     {
341         if ( src == null )
342         {
343             return null;
344         }
345         
346         Activation result = new Activation();
347         result.setActiveByDefault( src.isActiveByDefault() );
348         result.setFile( cloneActivationFile( src.getFile() ) );
349         result.setJdk( src.getJdk() );
350         result.setOs( cloneActivationOs( src.getOs() ) );
351         result.setProperty( cloneActivationProperty( src.getProperty() ) );
352         
353         return result;
354     }
355 
356     public static ActivationProperty cloneActivationProperty( ActivationProperty src )
357     {
358         if ( src == null )
359         {
360             return null;
361         }
362         
363         ActivationProperty result = new ActivationProperty();
364         
365         result.setName( src.getName() );
366         result.setValue( src.getValue() );
367         
368         return result;
369     }
370 
371     public static ActivationOS cloneActivationOs( ActivationOS src )
372     {
373         if ( src == null )
374         {
375             return null;
376         }
377         
378         ActivationOS result = new ActivationOS();
379         
380         result.setArch( src.getArch() );
381         result.setFamily( src.getFamily() );
382         result.setName( src.getName() );
383         result.setVersion( src.getVersion() );
384         
385         return result;
386     }
387 
388     public static ActivationFile cloneActivationFile( ActivationFile src )
389     {
390         if ( src == null )
391         {
392             return null;
393         }
394         
395         ActivationFile result = new ActivationFile();
396         
397         result.setExists( src.getExists() );
398         result.setMissing( src.getMissing() );
399 
400         return result;
401     }
402 
403     public static Repository cloneRepository( Repository src )
404     {
405         if ( src == null )
406         {
407             return null;
408         }
409         
410         Repository result = new Repository();
411         
412         result.setReleases( cloneRepositoryPolicy( src.getReleases() ) );
413         result.setSnapshots( cloneRepositoryPolicy( src.getSnapshots() ) );
414         
415         cloneRepositoryBaseFields( src, result );
416         
417         return result;
418     }
419 
420     public static RepositoryPolicy cloneRepositoryPolicy( RepositoryPolicy src )
421     {
422         if ( src == null )
423         {
424             return null;
425         }
426         
427         RepositoryPolicy result = new RepositoryPolicy();
428         
429         result.setChecksumPolicy( src.getChecksumPolicy() );
430         result.setEnabled( src.isEnabled() );
431         result.setUpdatePolicy( src.getUpdatePolicy() );
432         
433         return result;
434     }
435 
436     public static MailingList cloneMailingList( MailingList src )
437     {
438         if ( src == null )
439         {
440             return null;
441         }
442         
443         MailingList result = new MailingList();
444         
445         result.setArchive( src.getArchive() );
446         result.setName( src.getName() );
447         result.setOtherArchives( src.getOtherArchives() );
448         result.setPost( src.getPost() );
449         result.setSubscribe( src.getSubscribe() );
450         result.setUnsubscribe( src.getUnsubscribe() );
451         
452         return result;
453     }
454 
455     /**
456      * This should be the resulting ordering of plugins after merging:
457      *
458      * Given:
459      *
460      *   parent: X -> A -> B -> D -> E
461      *   child: Y -> A -> C -> D -> F
462      *
463      * Result:
464      *
465      *   X -> Y -> A -> B -> C -> D -> E -> F
466      */
467     public static void mergePluginLists( PluginContainer child, PluginContainer parent,
468                                          boolean handleAsInheritance )
469     {
470         if ( ( child == null ) || ( parent == null ) )
471         {
472             // nothing to do.
473             return;
474         }
475 
476         List parentPlugins = parent.getPlugins();
477 
478         if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
479         {
480             parentPlugins = new ArrayList( parentPlugins );
481 
482             // If we're processing this merge as an inheritance, we have to build up a list of
483             // plugins that were considered for inheritance.
484             if ( handleAsInheritance )
485             {
486                 for ( Iterator it = parentPlugins.iterator(); it.hasNext(); )
487                 {
488                     Plugin plugin = (Plugin) it.next();
489 
490                     String inherited = plugin.getInherited();
491 
492                     if ( ( inherited != null ) && !Boolean.valueOf( inherited ).booleanValue() )
493                     {
494                         it.remove();
495                     }
496                 }
497             }
498 
499             List assembledPlugins = new ArrayList();
500 
501             Map childPlugins = child.getPluginsAsMap();
502 
503             for ( Iterator it = parentPlugins.iterator(); it.hasNext(); )
504             {
505                 Plugin parentPlugin = (Plugin) it.next();
506 
507                 String parentInherited = parentPlugin.getInherited();
508 
509                 // only merge plugin definition from the parent if at least one
510                 // of these is true:
511                 // 1. we're not processing the plugins in an inheritance-based merge
512                 // 2. the parent's <inherited/> flag is not set
513                 // 3. the parent's <inherited/> flag is set to true
514                 if ( !handleAsInheritance || ( parentInherited == null ) ||
515                     Boolean.valueOf( parentInherited ).booleanValue() )
516                 {
517                     Plugin childPlugin = (Plugin) childPlugins.get( parentPlugin.getKey() );
518 
519                     if ( ( childPlugin != null ) && !assembledPlugins.contains( childPlugin ) )
520                     {
521                         Plugin assembledPlugin = childPlugin;
522 
523                         mergePluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
524 
525                         // fix for MNG-2221 (assembly cache was not being populated for later reference):
526                         assembledPlugins.add( assembledPlugin );
527                     }
528 
529                     // if we're processing this as an inheritance-based merge, and
530                     // the parent's <inherited/> flag is not set, then we need to
531                     // clear the inherited flag in the merge result.
532                     if ( handleAsInheritance && ( parentInherited == null ) )
533                     {
534                         parentPlugin.unsetInheritanceApplied();
535                     }
536                 }
537 
538                 // very important to use the parentPlugins List, rather than parentContainer.getPlugins()
539                 // since this list is a local one, and may have been modified during processing.
540                 List results = ModelUtils.orderAfterMerge( assembledPlugins, parentPlugins,
541                                                                         child.getPlugins() );
542 
543 
544                 child.setPlugins( results );
545 
546                 child.flushPluginMap();
547             }
548         }
549     }
550 
551     public static List orderAfterMerge( List merged, List highPrioritySource, List lowPrioritySource )
552     {
553         List results = new ArrayList();
554 
555         if ( !merged.isEmpty() )
556         {
557             results.addAll( merged );
558         }
559 
560         List missingFromResults = new ArrayList();
561 
562         List sources = new ArrayList();
563 
564         sources.add( highPrioritySource );
565         sources.add( lowPrioritySource );
566 
567         for ( Iterator sourceIterator = sources.iterator(); sourceIterator.hasNext(); )
568         {
569             List source = (List) sourceIterator.next();
570 
571             for ( Iterator it = source.iterator(); it.hasNext(); )
572             {
573                 Object item = it.next();
574 
575                 if ( results.contains( item ) )
576                 {
577                     if ( !missingFromResults.isEmpty() )
578                     {
579                         int idx = results.indexOf( item );
580 
581                         if ( idx < 0 )
582                         {
583                             idx = 0;
584                         }
585 
586                         results.addAll( idx, missingFromResults );
587 
588                         missingFromResults.clear();
589                     }
590                 }
591                 else
592                 {
593                     missingFromResults.add( item );
594                 }
595             }
596 
597             if ( !missingFromResults.isEmpty() )
598             {
599                 results.addAll( missingFromResults );
600 
601                 missingFromResults.clear();
602             }
603         }
604 
605         return results;
606     }
607 
608     /**
609      * Merge the list of reporting plugins from parent pom and child pom
610      * TODO it's pretty much a copy of {@link #mergePluginLists(PluginContainer, PluginContainer, boolean)}
611      * 
612      * @param child
613      * @param parent
614      * @param handleAsInheritance
615      */
616     public static void mergeReportPluginLists( Reporting child, Reporting parent, boolean handleAsInheritance )
617     {
618         if ( ( child == null ) || ( parent == null ) )
619         {
620             // nothing to do.
621             return;
622         }
623 
624         List parentPlugins = parent.getPlugins();
625 
626         if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
627         {
628             parentPlugins = new ArrayList( parentPlugins );
629 
630             // If we're processing this merge as an inheritance, we have to build up a list of
631             // plugins that were considered for inheritance.
632             if ( handleAsInheritance )
633             {
634                 for ( Iterator it = parentPlugins.iterator(); it.hasNext(); )
635                 {
636                     ReportPlugin plugin = (ReportPlugin) it.next();
637 
638                     String inherited = plugin.getInherited();
639 
640                     if ( ( inherited != null ) && !Boolean.valueOf( inherited ).booleanValue() )
641                     {
642                         it.remove();
643                     }
644                 }
645             }
646 
647             List assembledPlugins = new ArrayList();
648 
649             Map childPlugins = child.getReportPluginsAsMap();
650 
651             for ( Iterator it = parentPlugins.iterator(); it.hasNext(); )
652             {
653                 ReportPlugin parentPlugin = (ReportPlugin) it.next();
654 
655                 String parentInherited = parentPlugin.getInherited();
656 
657                 // only merge plugin definition from the parent if at least one
658                 // of these is true:
659                 // 1. we're not processing the plugins in an inheritance-based merge
660                 // 2. the parent's <inherited/> flag is not set
661                 // 3. the parent's <inherited/> flag is set to true
662                 if ( !handleAsInheritance || ( parentInherited == null ) ||
663                     Boolean.valueOf( parentInherited ).booleanValue() )
664                 {
665                     ReportPlugin childPlugin = (ReportPlugin) childPlugins.get( parentPlugin.getKey() );
666 
667                     if ( ( childPlugin != null ) && !assembledPlugins.contains( childPlugin ) )
668                     {
669                         ReportPlugin assembledPlugin = childPlugin;
670 
671                         mergeReportPluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
672 
673                         // fix for MNG-2221 (assembly cache was not being populated for later reference):
674                         assembledPlugins.add( assembledPlugin );
675                     }
676 
677                     // if we're processing this as an inheritance-based merge, and
678                     // the parent's <inherited/> flag is not set, then we need to
679                     // clear the inherited flag in the merge result.
680                     if ( handleAsInheritance && ( parentInherited == null ) )
681                     {
682                         parentPlugin.unsetInheritanceApplied();
683                     }
684                 }
685 
686                 // very important to use the parentPlugins List, rather than parentContainer.getPlugins()
687                 // since this list is a local one, and may have been modified during processing.
688                 List results = ModelUtils.orderAfterMerge( assembledPlugins, parentPlugins,
689                                                                         child.getPlugins() );
690 
691                 child.setPlugins( results );
692 
693                 child.flushReportPluginMap();
694             }
695         }
696     }
697 
698     public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean handleAsInheritance )
699     {
700         if ( ( child == null ) || ( parent == null ) )
701         {
702             // nothing to do.
703             return;
704         }
705 
706         if ( parent.isExtensions() )
707         {
708             child.setExtensions( true );
709         }
710 
711         if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
712         {
713             child.setVersion( parent.getVersion() );
714         }
715 
716         Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
717         Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
718 
719         childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
720 
721         child.setConfiguration( childConfiguration );
722 
723         child.setDependencies( mergeDependencyList( child.getDependencies(), parent.getDependencies() ) );
724 
725         // from here to the end of the method is dealing with merging of the <executions/> section.
726         String parentInherited = parent.getInherited();
727 
728         boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited ).booleanValue();
729 
730         List parentExecutions = parent.getExecutions();
731 
732         if ( ( parentExecutions != null ) && !parentExecutions.isEmpty() )
733         {
734             List mergedExecutions = new ArrayList();
735 
736             Map assembledExecutions = new TreeMap();
737 
738             Map childExecutions = child.getExecutionsAsMap();
739 
740             for ( Iterator it = parentExecutions.iterator(); it.hasNext(); )
741             {
742                 PluginExecution parentExecution = (PluginExecution) it.next();
743 
744                 String inherited = parentExecution.getInherited();
745 
746                 boolean parentExecInherited = parentIsInherited && ( ( inherited == null ) || Boolean.valueOf( inherited ).booleanValue() );
747 
748                 if ( !handleAsInheritance || parentExecInherited )
749                 {
750                     PluginExecution assembled = parentExecution;
751 
752                     PluginExecution childExecution = (PluginExecution) childExecutions.get( parentExecution.getId() );
753 
754                     if ( childExecution != null )
755                     {
756                         mergePluginExecutionDefinitions( childExecution, parentExecution );
757 
758                         assembled = childExecution;
759                     }
760                     else if ( handleAsInheritance && ( parentInherited == null ) )
761                     {
762                         parentExecution.unsetInheritanceApplied();
763                     }
764 
765                     assembledExecutions.put( assembled.getId(), assembled );
766                     mergedExecutions.add(assembled);
767                 }
768             }
769 
770             for ( Iterator it = child.getExecutions().iterator(); it.hasNext(); )
771             {
772                 PluginExecution childExecution = (PluginExecution)it.next();
773 
774                 if ( !assembledExecutions.containsKey( childExecution.getId() ) )
775                 {
776                     mergedExecutions.add(childExecution);
777                 }
778             }
779 
780             child.setExecutions(mergedExecutions);
781 
782             child.flushExecutionMap();
783         }
784 
785     }
786 
787     public static void mergeReportPluginDefinitions( ReportPlugin child, ReportPlugin parent,
788                                                      boolean handleAsInheritance )
789     {
790         if ( ( child == null ) || ( parent == null ) )
791         {
792             // nothing to do.
793             return;
794         }
795 
796         if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
797         {
798             child.setVersion( parent.getVersion() );
799         }
800 
801         String parentInherited = parent.getInherited();
802 
803         boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited ).booleanValue();
804 
805         // merge configuration just like with build plugins	
806         if ( parentIsInherited )
807         {
808             Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
809             Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
810 
811             childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
812 
813             child.setConfiguration( childConfiguration );
814         }
815 
816         // from here to the end of the method is dealing with merging of the <executions/> section.
817         List parentReportSets = parent.getReportSets();
818 
819         if ( ( parentReportSets != null ) && !parentReportSets.isEmpty() )
820         {
821             Map assembledReportSets = new TreeMap();
822 
823             Map childReportSets = child.getReportSetsAsMap();
824 
825             for ( Iterator it = parentReportSets.iterator(); it.hasNext(); )
826             {
827                 ReportSet parentReportSet = (ReportSet) it.next();
828 
829                 if ( !handleAsInheritance || parentIsInherited )
830                 {
831                     ReportSet assembledReportSet = parentReportSet;
832 
833                     ReportSet childReportSet = (ReportSet) childReportSets.get( parentReportSet.getId() );
834 
835                     if ( childReportSet != null )
836                     {
837                         mergeReportSetDefinitions( childReportSet, parentReportSet );
838 
839                         assembledReportSet = childReportSet;
840                     }
841                     else if ( handleAsInheritance && ( parentInherited == null ) )
842                     {
843                         parentReportSet.unsetInheritanceApplied();
844                     }
845 
846                     assembledReportSets.put( assembledReportSet.getId(), assembledReportSet );
847                 }
848             }
849 
850             for ( Iterator it = childReportSets.entrySet().iterator(); it.hasNext(); )
851             {
852                 Map.Entry entry = (Map.Entry) it.next();
853 
854                 String id = (String) entry.getKey();
855 
856                 if ( !assembledReportSets.containsKey( id ) )
857                 {
858                     assembledReportSets.put( id, entry.getValue() );
859                 }
860             }
861 
862             child.setReportSets( new ArrayList( assembledReportSets.values() ) );
863 
864             child.flushReportSetMap();
865         }
866 
867     }
868 
869     private static void mergePluginExecutionDefinitions( PluginExecution child, PluginExecution parent )
870     {
871         if ( child.getPhase() == null )
872         {
873             child.setPhase( parent.getPhase() );
874         }
875 
876         List parentGoals = parent.getGoals();
877         List childGoals = child.getGoals();
878 
879         List goals = new ArrayList();
880 
881         if ( ( childGoals != null ) && !childGoals.isEmpty() )
882         {
883             goals.addAll( childGoals );
884         }
885 
886         if ( parentGoals != null )
887         {
888             for ( Iterator goalIterator = parentGoals.iterator(); goalIterator.hasNext(); )
889             {
890                 String goal = (String) goalIterator.next();
891 
892                 if ( !goals.contains( goal ) )
893                 {
894                     goals.add( goal );
895                 }
896             }
897         }
898 
899         child.setGoals( goals );
900 
901         Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
902         Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
903 
904         childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
905 
906         child.setConfiguration( childConfiguration );
907     }
908 
909     private static void mergeReportSetDefinitions( ReportSet child, ReportSet parent )
910     {
911         List parentReports = parent.getReports();
912         List childReports = child.getReports();
913 
914         List reports = new ArrayList();
915 
916         if ( ( childReports != null ) && !childReports.isEmpty() )
917         {
918             reports.addAll( childReports );
919         }
920 
921         if ( parentReports != null )
922         {
923             for ( Iterator i = parentReports.iterator(); i.hasNext(); )
924             {
925                 String report = (String) i.next();
926 
927                 if ( !reports.contains( report ) )
928                 {
929                     reports.add( report );
930                 }
931             }
932         }
933 
934         child.setReports( reports );
935 
936         Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
937         Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
938 
939         childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
940 
941         child.setConfiguration( childConfiguration );
942     }
943 
944     public static Model cloneModel( Model src )
945     {
946         if ( src == null )
947         {
948             return null;
949         }
950         
951         Model result = new Model();
952         
953         cloneModelBaseFields( src, result );
954 
955         result.setArtifactId( src.getArtifactId() );
956         result.setBuild( cloneBuild( src.getBuild() ) );
957         result.setCiManagement( cloneCiManagement( src.getCiManagement() ) );
958         
959         result.setContributors( cloneList( src.getContributors(), CONTRIBUTOR_CLONER ) );
960         
961         result.setDescription( src.getDescription() );
962         result.setDevelopers( cloneList( src.getDevelopers(), DEVELOPER_CLONER ) );
963         
964         result.setGroupId( src.getGroupId() );
965         result.setInceptionYear( src.getInceptionYear() );
966         result.setIssueManagement( cloneIssueManagement( src.getIssueManagement() ) );
967         result.setLicenses( cloneList( src.getLicenses(), LICENSE_CLONER ) );
968         
969         result.setMailingLists( cloneList( src.getMailingLists(), MAILING_LIST_CLONER ) );
970         result.setModelVersion( src.getModelVersion() );
971         result.setName( src.getName() );
972         result.setOrganization( cloneOrganization( src.getOrganization() ) );
973         result.setPackaging( src.getPackaging() );
974         result.setParent( cloneParent( src.getParent() ) );
975         
976         result.setPrerequisites( clonePrerequisites( src.getPrerequisites() ) );
977         result.setProfiles( cloneList( src.getProfiles(), PROFILE_CLONER ) );
978         
979         result.setScm( cloneScm( src.getScm() ) );
980         result.setUrl( src.getUrl() );
981         result.setVersion( src.getVersion() );
982 
983         return result;
984     }
985 
986     public static Scm cloneScm( Scm src )
987     {
988         if ( src == null )
989         {
990             return null;
991         }
992         
993         Scm result = new Scm();
994         
995         result.setConnection( src.getConnection() );
996         result.setDeveloperConnection( src.getDeveloperConnection() );
997         result.setTag( src.getTag() );
998         result.setUrl( src.getUrl() );
999         
1000         return result;
1001     }
1002 
1003     public static Prerequisites clonePrerequisites( Prerequisites src )
1004     {
1005         if ( src == null )
1006         {
1007             return null;
1008         }
1009         
1010         Prerequisites result = new Prerequisites();
1011         
1012         result.setMaven( src.getMaven() );
1013 
1014         return result;
1015     }
1016 
1017     public static Organization cloneOrganization( Organization src )
1018     {
1019         if ( src == null )
1020         {
1021             return null;
1022         }
1023         
1024         Organization result = new Organization();
1025         
1026         result.setName( src.getName() );
1027         result.setUrl( src.getUrl() );
1028         
1029         return result;
1030     }
1031 
1032     public static License cloneLicense( License src )
1033     {
1034         if ( src == null )
1035         {
1036             return null;
1037         }
1038         
1039         License result = new License();
1040         
1041         result.setComments( src.getComments() );
1042         result.setDistribution( src.getDistribution() );
1043         result.setName( src.getName() );
1044         result.setUrl( src.getUrl() );
1045         
1046         return result;
1047     }
1048 
1049     public static IssueManagement cloneIssueManagement( IssueManagement src )
1050     {
1051         if ( src == null )
1052         {
1053             return null;
1054         }
1055         
1056         IssueManagement result = new IssueManagement();
1057         
1058         result.setSystem( src.getSystem() );
1059         result.setUrl( src.getUrl() );
1060         
1061         return result;
1062     }
1063 
1064     public static DistributionManagement cloneDistributionManagement( DistributionManagement src )
1065     {
1066         if ( src == null )
1067         {
1068             return null;
1069         }
1070         
1071         DistributionManagement result = new DistributionManagement();
1072         
1073         result.setDownloadUrl( src.getDownloadUrl() );
1074         result.setRelocation( cloneRelocation( src.getRelocation() ) );
1075         result.setRepository( cloneDeploymentRepository( src.getRepository() ) );
1076         result.setSite( cloneSite( src.getSite() ) );
1077         result.setSnapshotRepository( cloneDeploymentRepository( src.getSnapshotRepository() ) );
1078         result.setStatus( src.getStatus() );
1079         
1080         return result;
1081     }
1082 
1083     public static Site cloneSite( Site src )
1084     {
1085         if ( src == null )
1086         {
1087             return null;
1088         }
1089         
1090         Site result = new Site();
1091         
1092         result.setId( src.getId() );
1093         result.setName( src.getName() );
1094         result.setUrl( src.getUrl() );
1095         
1096         return result;
1097     }
1098 
1099     public static DeploymentRepository cloneDeploymentRepository( DeploymentRepository src )
1100     {
1101         if ( src == null )
1102         {
1103             return null;
1104         }
1105         
1106         DeploymentRepository result = new DeploymentRepository();
1107         
1108         result.setUniqueVersion( src.isUniqueVersion() );
1109         
1110         cloneRepositoryBaseFields( src, result );
1111         
1112         return result;
1113     }
1114 
1115     private static void cloneRepositoryBaseFields( RepositoryBase src, RepositoryBase result )
1116     {
1117         result.setId( src.getId() );
1118         result.setLayout( src.getLayout() );
1119         result.setName( src.getName() );
1120         result.setUrl( src.getUrl() );
1121     }
1122 
1123     public static Relocation cloneRelocation( Relocation src )
1124     {
1125         if ( src == null )
1126         {
1127             return null;
1128         }
1129         
1130         Relocation result = new Relocation();
1131         
1132         result.setArtifactId( src.getArtifactId() );
1133         result.setGroupId( src.getGroupId() );
1134         result.setMessage( src.getMessage() );
1135         result.setVersion( src.getVersion() );
1136         
1137         return result;
1138     }
1139 
1140     public static DependencyManagement cloneDependencyManagement( DependencyManagement src )
1141     {
1142         if ( src == null )
1143         {
1144             return null;
1145         }
1146         
1147         DependencyManagement result = new DependencyManagement();
1148         result.setDependencies( cloneList( src.getDependencies(), DEPENDENCY_CLONER ) );
1149         
1150         return result;
1151     }
1152 
1153     private static List cloneList( List src, ModelPartCloner cloner )
1154     {
1155         List result = null;
1156         if ( src != null )
1157         {
1158             result = new ArrayList( src.size() );
1159             for ( Iterator it = src.iterator(); it.hasNext(); )
1160             {
1161                 result.add( cloner.cloneModelPart( (Object) it.next() ) );
1162             }
1163         }
1164         
1165         return result;
1166     }
1167 
1168     public static Contributor cloneContributor( Contributor src )
1169     {
1170         if ( src == null )
1171         {
1172             return null;
1173         }
1174         
1175         Contributor result = new Contributor();
1176         cloneContributorFields( src, result );
1177         
1178         return result;
1179     }
1180     
1181     public static Developer cloneDeveloper( Developer src )
1182     {
1183         if ( src == null )
1184         {
1185             return null;
1186         }
1187         
1188         Developer result = new Developer();
1189         
1190         result.setId( src.getId() );
1191         
1192         cloneContributorFields( src, result );
1193         
1194         return result;
1195     }
1196     
1197     private static void cloneContributorFields( Contributor src, Contributor result )
1198     {
1199         result.setEmail( src.getEmail() );
1200         result.setName( src.getName() );
1201         result.setOrganization( src.getOrganization() );
1202         result.setOrganizationUrl( src.getOrganizationUrl() );
1203         result.setProperties( cloneProperties( src.getProperties() ) );
1204         result.setRoles( cloneListOfStrings( src.getRoles() ) );
1205         result.setTimezone( src.getTimezone() );
1206         result.setUrl( src.getUrl() );
1207     }
1208 
1209     public static CiManagement cloneCiManagement( CiManagement src )
1210     {
1211         if ( src == null )
1212         {
1213             return null;
1214         }
1215         
1216         CiManagement result = new CiManagement();
1217         
1218         List notifiers = null;
1219         if ( src.getNotifiers() != null )
1220         {
1221             notifiers = new ArrayList( src.getNotifiers().size() );
1222             for ( Iterator it = src.getNotifiers().iterator(); it.hasNext(); )
1223             {
1224                 notifiers.add( cloneNotifier( (Notifier) it.next() ) );
1225             }
1226         }
1227         result.setNotifiers( cloneList( src.getNotifiers(), NOTIFIER_CLONER ) );
1228         
1229         result.setSystem( src.getSystem() );
1230         result.setUrl( src.getUrl() );
1231         
1232         return result;
1233     }
1234 
1235     public static Notifier cloneNotifier( Notifier src )
1236     {
1237         if ( src == null )
1238         {
1239             return null;
1240         }
1241         
1242         Notifier result = new Notifier();
1243         result.setAddress( src.getAddress() );
1244         result.setConfiguration( cloneProperties( src.getConfiguration() ) );
1245         result.setSendOnError( src.isSendOnError() );
1246         result.setSendOnFailure( result.isSendOnFailure() );
1247         result.setSendOnSuccess( result.isSendOnSuccess() );
1248         result.setSendOnWarning( result.isSendOnWarning() );
1249         
1250         return result;
1251     }
1252 
1253     public static Properties cloneProperties( Properties src )
1254     {
1255         if ( src == null )
1256         {
1257             return null;
1258         }
1259         
1260         Properties result = new Properties();
1261         for( Enumeration e = src.propertyNames(); e.hasMoreElements(); )
1262         {
1263             String key = (String) e.nextElement();
1264             result.setProperty( key, src.getProperty( key ) );
1265         }
1266         
1267         return result;
1268     }
1269 
1270     public static Build cloneBuild( Build src )
1271     {
1272         if ( src == null )
1273         {
1274             return null;
1275         }
1276 
1277         Build result = new Build();
1278         
1279         cloneBuildBaseFields( src, result );
1280         
1281         result.setExtensions( cloneList( src.getExtensions(), EXTENSION_CLONER ) );
1282         result.setOutputDirectory( src.getOutputDirectory() );
1283         
1284         result.setScriptSourceDirectory( src.getScriptSourceDirectory() );
1285         result.setSourceDirectory( src.getSourceDirectory() );
1286         result.setTestOutputDirectory( src.getTestOutputDirectory() );
1287         result.setTestSourceDirectory( src.getTestSourceDirectory() );
1288         
1289         return result;
1290     }
1291 
1292     public static void cloneBuildBaseFields( BuildBase src, BuildBase result )
1293     {
1294         result.setDefaultGoal( src.getDefaultGoal() );
1295         result.setDirectory( src.getDirectory() );
1296         
1297         result.setFilters( cloneListOfStrings( src.getFilters() ) );
1298         result.setFinalName( src.getFinalName() );
1299         
1300         result.setPluginManagement( clonePluginManagement( src.getPluginManagement() ) );
1301         result.setPlugins( cloneList( src.getPlugins(), PLUGIN_CLONER ) );
1302  
1303         result.setResources( cloneList( src.getResources(), RESOURCE_CLONER ) );
1304         
1305         result.setTestResources( cloneList( src.getTestResources(), RESOURCE_CLONER ) );
1306     }
1307 
1308     public static PluginManagement clonePluginManagement( PluginManagement src )
1309     {
1310         PluginManagement pMgmt = null;
1311         if ( src != null )
1312         {
1313             pMgmt = new PluginManagement();
1314             pMgmt.setPlugins( cloneList( src.getPlugins(), PLUGIN_CLONER ) );
1315         }
1316         
1317         return pMgmt;
1318     }
1319 
1320     public static Resource cloneResource( Resource src )
1321     {
1322         Resource result = null;
1323         if ( src != null )
1324         {
1325             result = new Resource();
1326             
1327             result.setDirectory( src.getDirectory() );
1328             result.setExcludes( cloneListOfStrings( src.getExcludes() ) );
1329             result.setFiltering( src.isFiltering() );
1330             result.setIncludes( cloneListOfStrings( src.getIncludes() ) );
1331             result.setMergeId( src.getMergeId() );
1332             result.setTargetPath( src.getTargetPath() );
1333         }
1334         
1335         return result;
1336     }
1337 
1338     public static Plugin clonePlugin( Plugin src )
1339     {
1340         Plugin result = null;
1341         if ( src != null )
1342         {
1343             result = new Plugin();
1344             result.setArtifactId( src.getArtifactId() );
1345             
1346             result.setConfiguration( cloneConfiguration( src.getConfiguration() ) );
1347             
1348             result.setDependencies( cloneList( src.getDependencies(), DEPENDENCY_CLONER ) );
1349             result.setExecutions( cloneList( src.getExecutions(), PLUGIN_EXECUTION_CLONER ) );
1350             
1351             result.setExtensions( src.isExtensions() );
1352             result.setGroupId( src.getGroupId() );
1353             result.setInherited( src.getInherited() );
1354             result.setVersion( src.getVersion() );
1355         }
1356         
1357         return result;
1358     }
1359 
1360     public static PluginExecution clonePluginExecution( PluginExecution src )
1361     {
1362         PluginExecution result = null;
1363         
1364         if ( src != null )
1365         {
1366             result = new PluginExecution();
1367             
1368             result.setId( src.getId() );
1369             result.setGoals( cloneListOfStrings( src.getGoals() ) );
1370             result.setConfiguration( cloneConfiguration( src.getConfiguration() ) );
1371             result.setInherited( src.getInherited() );
1372             result.setPhase( src.getPhase() );
1373         }
1374         
1375         return result;
1376     }
1377 
1378     // FIXME: We need something better than this for configurations!
1379     public static Object cloneConfiguration( Object configuration )
1380     {
1381         if ( configuration == null )
1382         {
1383             return null;
1384         }
1385         
1386         return new Xpp3Dom( (Xpp3Dom) configuration );
1387     }
1388 
1389     public static Dependency cloneDependency( Dependency src )
1390     {
1391         Dependency result = null;
1392         if ( src != null )
1393         {
1394             result = new Dependency();
1395             
1396             result.setArtifactId( src.getArtifactId() );
1397             result.setClassifier( src.getClassifier() );
1398             result.setExclusions( cloneList( src.getExclusions(), DEPENDENCY_EXCLUSION_CLONER ) );
1399             result.setGroupId( src.getGroupId() );
1400             result.setOptional( src.isOptional() );
1401             result.setScope( src.getScope() );
1402             result.setSystemPath( src.getSystemPath() );
1403             result.setType( src.getType() );
1404             result.setVersion( src.getVersion() );
1405         }
1406         
1407         return result;
1408     }
1409 
1410     public static Exclusion cloneExclusion( Exclusion src )
1411     {
1412         Exclusion result = null;
1413         if ( src != null )
1414         {
1415             result = new Exclusion();
1416             result.setArtifactId( src.getArtifactId() );
1417             result.setGroupId( src.getGroupId() );
1418         }
1419         
1420         return result;
1421     }
1422 
1423     public static List cloneListOfStrings( List src )
1424     {
1425         List result = null;
1426         if ( src != null )
1427         {
1428             result = new ArrayList( src.size() );
1429             for ( Iterator it = src.iterator(); it.hasNext(); )
1430             {
1431                 String item = (String) it.next();
1432                 result.add( item );
1433             }
1434         }
1435         
1436         return result;
1437     }
1438 
1439     public static Extension cloneExtension( Extension src )
1440     {
1441         Extension rExt = new Extension();
1442         rExt.setArtifactId( src.getArtifactId() );
1443         rExt.setGroupId( src.getGroupId() );
1444         rExt.setVersion( src.getVersion() );
1445         
1446         return rExt;
1447     }
1448 
1449     public static Exclusion cloneDependencyExclusion( Exclusion src )
1450     {
1451         if ( src == null )
1452         {
1453             return null;
1454         }
1455         
1456         Exclusion result = new Exclusion();
1457 
1458         result.setArtifactId( src.getArtifactId() );
1459         result.setGroupId( src.getGroupId() );
1460         
1461         return result;
1462     }
1463 
1464     public static Parent cloneParent( Parent src )
1465     {
1466         if ( src == null )
1467         {
1468             return null;
1469         }
1470 
1471         Parent result = new Parent();
1472         result.setArtifactId( src.getArtifactId() );
1473         result.setGroupId( src.getGroupId() );
1474         result.setRelativePath( src.getRelativePath() );
1475         result.setVersion( src.getVersion() );
1476         
1477         return result;
1478     }
1479 
1480     public static List mergeRepositoryLists( List dominant, List recessive )
1481     {
1482         List repositories = new ArrayList();
1483 
1484         for ( Iterator it = dominant.iterator(); it.hasNext(); )
1485         {
1486             Repository repository = (Repository) it.next();
1487 
1488             repositories.add( repository );
1489         }
1490 
1491         for ( Iterator it = recessive.iterator(); it.hasNext(); )
1492         {
1493             Repository repository = (Repository) it.next();
1494 
1495             if ( !repositories.contains( repository ) )
1496             {
1497                 repositories.add( repository );
1498             }
1499         }
1500 
1501         return repositories;
1502     }
1503 
1504     public static void mergeExtensionLists( Build childBuild, Build parentBuild )
1505     {
1506         Map extMap = new LinkedHashMap();
1507 
1508         List ext = childBuild.getExtensions();
1509 
1510         if ( ext != null )
1511         {
1512             for ( Iterator it = ext.iterator(); it.hasNext(); )
1513             {
1514                 Extension extension = (Extension) it.next();
1515                 extMap.put( extension.getKey(), extension );
1516             }
1517         }
1518 
1519         ext = parentBuild.getExtensions();
1520 
1521         if ( ext != null )
1522         {
1523             for ( Iterator it = ext.iterator(); it.hasNext(); )
1524             {
1525                 Extension extension = (Extension) it.next();
1526                 if ( !extMap.containsKey( extension.getKey() ) )
1527                 {
1528                     extMap.put( extension.getKey(), extension );
1529                 }
1530             }
1531         }
1532 
1533         childBuild.setExtensions( new ArrayList( extMap.values() ) );
1534     }
1535 
1536     public static void mergeResourceLists( List childResources, List parentResources )
1537     {
1538         for ( Iterator i = parentResources.iterator(); i.hasNext(); )
1539         {
1540             Resource r = (Resource) i.next();
1541             if ( !childResources.contains( r ) )
1542             {
1543                 childResources.add( r );
1544             }
1545         }
1546     }
1547 
1548     public static void mergeFilterLists( List childFilters, List parentFilters )
1549     {
1550         for ( Iterator i = parentFilters.iterator(); i.hasNext(); )
1551         {
1552             String f = (String) i.next();
1553             if ( !childFilters.contains( f ) )
1554             {
1555                 childFilters.add( f );
1556             }
1557         }
1558     }
1559 
1560     public static List mergeDependencyList( List child, List parent )
1561     {
1562         Map depsMap = new LinkedHashMap();
1563 
1564         if ( child != null )
1565         {
1566             for ( Iterator it = child.iterator(); it.hasNext(); )
1567             {
1568                 Dependency dependency = (Dependency) it.next();
1569                 depsMap.put( dependency.getManagementKey(), dependency );
1570             }
1571         }
1572 
1573         if ( parent != null )
1574         {
1575             for ( Iterator it = parent.iterator(); it.hasNext(); )
1576             {
1577                 Dependency dependency = (Dependency) it.next();
1578                 if ( !depsMap.containsKey( dependency.getManagementKey() ) )
1579                 {
1580                     depsMap.put( dependency.getManagementKey(), dependency );
1581                 }
1582             }
1583         }
1584 
1585         return new ArrayList( depsMap.values() );
1586     }
1587     
1588     public static interface ModelPartCloner
1589     {
1590         Object cloneModelPart( Object src );
1591     }
1592     
1593 
1594 }