]> source.dussan.org Git - archiva.git/blob
84b8745645b91292f3b7d9924cf987e7b311df43
[archiva.git] /
1 package org.apache.maven.archiva.repository.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 org.apache.commons.lang.StringUtils;
23 import org.apache.maven.archiva.model.ArchivaModelCloner;
24 import org.apache.maven.archiva.model.ArchivaProjectModel;
25 import org.apache.maven.archiva.model.ArtifactReference;
26 import org.apache.maven.archiva.model.CiManagement;
27 import org.apache.maven.archiva.model.Dependency;
28 import org.apache.maven.archiva.model.Exclusion;
29 import org.apache.maven.archiva.model.Individual;
30 import org.apache.maven.archiva.model.IssueManagement;
31 import org.apache.maven.archiva.model.License;
32 import org.apache.maven.archiva.model.Organization;
33 import org.apache.maven.archiva.model.ProjectRepository;
34 import org.apache.maven.archiva.model.Scm;
35
36 import java.util.ArrayList;
37 import java.util.Enumeration;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Properties;
44 import java.util.Set;
45 import java.util.Map.Entry;
46
47 /**
48  * ProjectModelMerge
49  *
50  * TODO: Should call this ProjectModelAncestry as it deals with the current project and its parent.
51  *
52  * @version $Id$
53  */
54 public class ProjectModelMerge
55 {
56     /**
57      * Merge the contents of a project with it's parent project.
58      * 
59      * @param mainProject the main project.
60      * @param parentProject the parent project to merge.
61      * @throws ProjectModelException if there was a problem merging the model.
62      */
63     public static ArchivaProjectModel merge( ArchivaProjectModel mainProject, ArchivaProjectModel parentProject )
64         throws ProjectModelException
65     {
66         if ( mainProject == null )
67         {
68             throw new ProjectModelException( "Cannot merge with a null main project." );
69         }
70
71         if ( parentProject == null )
72         {
73             throw new ProjectModelException( "Cannot merge with a null parent project." );
74         }
75
76         ArchivaProjectModel merged = new ArchivaProjectModel();
77
78         // Unmerged.
79         merged.setParentProject(mainProject.getParentProject());
80         merged.setArtifactId( mainProject.getArtifactId() );
81         merged.setPackaging( StringUtils.defaultIfEmpty( mainProject.getPackaging(), "jar" ) );
82         merged.setRelocation( mainProject.getRelocation() );
83
84         // Merged
85         merged.setGroupId( merge( mainProject.getGroupId(), parentProject.getGroupId() ) );
86         merged.setVersion( merge( mainProject.getVersion(), parentProject.getVersion() ) );
87         merged.setName( merge( mainProject.getName(), parentProject.getName() ) );
88         merged.setUrl( merge( mainProject.getUrl(), parentProject.getUrl() ) );
89         merged.setDescription( merge( mainProject.getDescription(), parentProject.getDescription() ) );
90
91         merged.setOrigin( "merged" );
92
93         merged.setCiManagement( merge( mainProject.getCiManagement(), parentProject.getCiManagement() ) );
94         merged.setIndividuals( mergeIndividuals( mainProject.getIndividuals(), parentProject.getIndividuals() ) );
95         merged.setIssueManagement( merge( mainProject.getIssueManagement(), parentProject.getIssueManagement() ) );
96         merged.setLicenses( mergeLicenses( mainProject.getLicenses(), parentProject.getLicenses() ) );
97         merged.setOrganization( merge( mainProject.getOrganization(), parentProject.getOrganization() ) );
98         merged.setScm( merge( mainProject.getScm(), parentProject.getScm() ) );
99         merged.setRepositories( mergeRepositories( mainProject.getRepositories(), parentProject.getRepositories() ) );
100         merged.setDependencies( mergeDependencies( mainProject.getDependencies(), parentProject.getDependencies() ) );
101         merged.setDependencyManagement( mergeDependencyManagement( mainProject.getDependencyManagement(), parentProject
102             .getDependencyManagement() ) );
103         merged.setPlugins( mergePlugins( mainProject.getPlugins(), parentProject.getPlugins() ) );
104         merged.setReports( mergeReports( mainProject.getReports(), parentProject.getReports() ) );
105         merged.setProperties( merge( mainProject.getProperties(), parentProject.getProperties() ) );
106         
107         return merged;
108     }
109
110     private static Map createArtifactReferenceMap( List artifactReferences )
111     {
112         Map ret = new HashMap();
113
114         Iterator it = artifactReferences.iterator();
115         while ( it.hasNext() )
116         {
117             ArtifactReference artifactReference = (ArtifactReference) it.next();
118             String key = toVersionlessArtifactKey( artifactReference );
119             ret.put( key, artifactReference );
120         }
121
122         return ret;
123     }
124
125     private static Map createDependencyMap( List dependencies )
126     {
127         Map ret = new HashMap();
128
129         Iterator it = dependencies.iterator();
130         while ( it.hasNext() )
131         {
132             Dependency dep = (Dependency) it.next();
133             String key = toVersionlessDependencyKey( dep );
134             ret.put( key, dep );
135         }
136
137         return ret;
138     }
139
140     private static Map createExclusionMap( List exclusions )
141     {
142         Map ret = new HashMap();
143
144         Iterator it = exclusions.iterator();
145         while ( it.hasNext() )
146         {
147             Exclusion exclusion = (Exclusion) it.next();
148             String key = exclusion.getGroupId() + ":" + exclusion.getArtifactId();
149             ret.put( key, exclusion );
150         }
151
152         return ret;
153     }
154
155     private static Map createLicensesMap( List licenses )
156     {
157         Map ret = new HashMap();
158
159         Iterator it = licenses.iterator();
160         while ( it.hasNext() )
161         {
162             License license = (License) it.next();
163             // TODO: Change to 'id' when LicenseTypeMapper is created.
164             String key = license.getName();
165             ret.put( key, license );
166         }
167
168         return ret;
169     }
170
171     private static Map createRepositoriesMap( List repositories )
172     {
173         Map ret = new HashMap();
174
175         Iterator it = repositories.iterator();
176         while ( it.hasNext() )
177         {
178             ProjectRepository repo = (ProjectRepository) it.next();
179             // Should this really be using repo.id ?
180             String key = repo.getUrl();
181             ret.put( key, repo );
182         }
183
184         return ret;
185     }
186
187     private static boolean empty( String val )
188     {
189         if ( val == null )
190         {
191             return true;
192         }
193
194         return ( val.trim().length() <= 0 );
195     }
196
197     private static ArtifactReference merge( ArtifactReference mainArtifactReference,
198                                             ArtifactReference parentArtifactReference )
199     {
200         if ( parentArtifactReference == null )
201         {
202             return mainArtifactReference;
203         }
204
205         if ( mainArtifactReference == null )
206         {
207             return ArchivaModelCloner.clone( parentArtifactReference );
208         }
209
210         ArtifactReference merged = new ArtifactReference();
211
212         // Unmerged.
213         merged.setGroupId( mainArtifactReference.getGroupId() );
214         merged.setArtifactId( mainArtifactReference.getArtifactId() );
215
216         // Merged.
217         merged.setVersion( merge( mainArtifactReference.getVersion(), parentArtifactReference.getVersion() ) );
218         merged.setClassifier( merge( mainArtifactReference.getClassifier(), parentArtifactReference.getClassifier() ) );
219         merged.setType( merge( mainArtifactReference.getType(), parentArtifactReference.getType() ) );
220
221         return merged;
222     }
223
224     private static CiManagement merge( CiManagement mainCim, CiManagement parentCim )
225     {
226         if ( parentCim == null )
227         {
228             return mainCim;
229         }
230
231         if ( mainCim == null )
232         {
233             return ArchivaModelCloner.clone( parentCim );
234         }
235
236         CiManagement merged = new CiManagement();
237
238         merged.setSystem( merge( mainCim.getSystem(), parentCim.getSystem() ) );
239         merged.setUrl( merge( mainCim.getUrl(), parentCim.getUrl() ) );
240
241         return merged;
242     }
243
244     private static Dependency merge( Dependency mainDep, Dependency parentDep )
245     {
246         if ( parentDep == null )
247         {
248             return mainDep;
249         }
250
251         if ( mainDep == null )
252         {
253             Dependency dep = ArchivaModelCloner.clone( parentDep );
254             dep.setFromParent( true );
255             return dep;
256         }
257
258         Dependency merged = new Dependency();
259
260         merged.setFromParent( true );
261
262         // Unmerged.
263         merged.setGroupId( mainDep.getGroupId() );
264         merged.setArtifactId( mainDep.getArtifactId() );
265
266         // Merged.
267         merged.setVersion( merge( mainDep.getVersion(), parentDep.getVersion() ) );
268         merged.setClassifier( merge( mainDep.getClassifier(), parentDep.getClassifier() ) );
269         merged.setType( merge( mainDep.getType(), parentDep.getType() ) );
270         merged.setScope( merge( mainDep.getScope(), parentDep.getScope() ) );
271         if ( parentDep.isOptional() )
272         {
273             merged.setOptional( true );
274         }
275
276         merged.setSystemPath( merge( mainDep.getSystemPath(), parentDep.getSystemPath() ) );
277         merged.setUrl( merge( mainDep.getUrl(), parentDep.getUrl() ) );
278         merged.setExclusions( mergeExclusions( mainDep.getExclusions(), parentDep.getExclusions() ) );
279
280         return merged;
281     }
282
283     private static IssueManagement merge( IssueManagement mainIssueManagement, IssueManagement parentIssueManagement )
284     {
285         if ( parentIssueManagement == null )
286         {
287             return mainIssueManagement;
288         }
289
290         if ( mainIssueManagement == null )
291         {
292             return ArchivaModelCloner.clone( parentIssueManagement );
293         }
294
295         IssueManagement merged = new IssueManagement();
296
297         merged.setSystem( merge( mainIssueManagement.getSystem(), parentIssueManagement.getSystem() ) );
298         merged.setUrl( merge( mainIssueManagement.getUrl(), parentIssueManagement.getUrl() ) );
299
300         return merged;
301     }
302
303     private static Organization merge( Organization mainOrganization, Organization parentOrganization )
304     {
305         if ( parentOrganization == null )
306         {
307             return mainOrganization;
308         }
309
310         if ( mainOrganization == null )
311         {
312             return ArchivaModelCloner.clone( parentOrganization );
313         }
314
315         Organization merged = new Organization();
316
317         merged.setFavicon( merge( mainOrganization.getFavicon(), parentOrganization.getFavicon() ) );
318         merged.setName( merge( mainOrganization.getName(), parentOrganization.getName() ) );
319         merged.setUrl( merge( mainOrganization.getUrl(), parentOrganization.getUrl() ) );
320
321         return merged;
322     }
323
324     private static Properties merge( Properties mainProperties, Properties parentProperties )
325     {
326         if ( parentProperties == null )
327         {
328             return mainProperties;
329         }
330
331         if ( mainProperties == null )
332         {
333             return ArchivaModelCloner.clone( parentProperties );
334         }
335
336         Properties merged = new Properties();
337         merged.putAll(mainProperties);
338
339         Enumeration keys = parentProperties.propertyNames();
340         while ( keys.hasMoreElements() )
341         {
342             String key = (String) keys.nextElement();
343             merged.put( key, merge( mainProperties.getProperty( key ), parentProperties.getProperty( key ) ) );
344         }
345
346         return merged;
347     }
348
349     private static Scm merge( Scm mainScm, Scm parentScm )
350     {
351         if ( parentScm == null )
352         {
353             return mainScm;
354         }
355
356         if ( mainScm == null )
357         {
358             return ArchivaModelCloner.clone( parentScm );
359         }
360
361         Scm merged = new Scm();
362
363         merged.setConnection( merge( mainScm.getConnection(), parentScm.getConnection() ) );
364         merged.setDeveloperConnection( merge( mainScm.getDeveloperConnection(), parentScm.getDeveloperConnection() ) );
365         merged.setUrl( merge( mainScm.getUrl(), parentScm.getUrl() ) );
366
367         return merged;
368     }
369
370     private static String merge( String main, String parent )
371     {
372         if ( empty( main ) && !empty( parent ) )
373         {
374             return parent;
375         }
376
377         return main;
378     }
379
380     private static List mergeArtifactReferences( List mainArtifactReferences, List parentArtifactReferences )
381     {
382         if ( parentArtifactReferences == null )
383         {
384             return mainArtifactReferences;
385         }
386
387         if ( mainArtifactReferences == null )
388         {
389             return ArchivaModelCloner.cloneLicenses( parentArtifactReferences );
390         }
391
392         List merged = new ArrayList();
393
394         Map mainArtifactReferenceMap = createArtifactReferenceMap( mainArtifactReferences );
395         Map parentArtifactReferenceMap = createArtifactReferenceMap( parentArtifactReferences );
396
397         Iterator it = mainArtifactReferenceMap.entrySet().iterator();
398         while ( it.hasNext() )
399         {
400             Map.Entry entry = (Entry) it.next();
401             String key = (String) entry.getKey();
402             ArtifactReference mainArtifactReference = (ArtifactReference) entry.getValue();
403             ArtifactReference parentArtifactReference = (ArtifactReference) parentArtifactReferenceMap.get( key );
404
405             if ( parentArtifactReference == null )
406             {
407                 merged.add( mainArtifactReference );
408             }
409             else
410             {
411                 // Not merging. Local wins.
412                 merged.add( merge( mainArtifactReference, parentArtifactReference ) );
413             }
414         }
415
416         return merged;
417     }
418
419     private static List mergeDependencies( List mainDependencies, List parentDependencies )
420     {
421         if ( parentDependencies == null )
422         {
423             return mainDependencies;
424         }
425
426         if ( mainDependencies == null )
427         {
428             List merged = ArchivaModelCloner.cloneDependencies( parentDependencies );
429             Iterator it = merged.iterator();
430             while ( it.hasNext() )
431             {
432                 Dependency dep = (Dependency) it.next();
433                 dep.setFromParent( true );
434             }
435             return merged;
436         }
437
438         List merged = new ArrayList();
439
440         Map mainDepMap = createDependencyMap( mainDependencies );
441         Map parentDepMap = createDependencyMap( parentDependencies );
442         Set uniqueKeys = new HashSet();
443         uniqueKeys.addAll( mainDepMap.keySet() );
444         uniqueKeys.addAll( parentDepMap.keySet() );
445
446         Iterator it = uniqueKeys.iterator();
447         while ( it.hasNext() )
448         {
449             String key = (String) it.next();
450             Dependency parentDep = (Dependency) parentDepMap.get( key );
451             Dependency mainDep = (Dependency) mainDepMap.get( key );
452
453             if ( parentDep == null )
454             {
455                 // Means there is no parent dep to override main dep.
456                 merged.add( mainDep );
457             }
458             else
459             {
460                 // Parent dep exists (main doesn't have to).
461                 // Merge the parent over the main dep.
462                 merged.add( merge( mainDep, parentDep ) );
463             }
464         }
465
466         return merged;
467     }
468
469     private static List mergeDependencyManagement( List mainDepMgmt, List parentDepMgmt )
470     {
471         if ( parentDepMgmt == null )
472         {
473             return mainDepMgmt;
474         }
475
476         if ( mainDepMgmt == null )
477         {
478             List merged = ArchivaModelCloner.cloneDependencies( parentDepMgmt );
479             Iterator it = merged.iterator();
480             while ( it.hasNext() )
481             {
482                 Dependency dep = (Dependency) it.next();
483                 dep.setFromParent( true );
484             }
485             return merged;
486         }
487
488         List merged = new ArrayList();
489
490         Map mainDepMap = createDependencyMap( mainDepMgmt );
491         Map parentDepMap = createDependencyMap( parentDepMgmt );
492         Set uniqueKeys = new HashSet();
493         uniqueKeys.addAll( mainDepMap.keySet() );
494         uniqueKeys.addAll( parentDepMap.keySet() );
495
496         Iterator it = uniqueKeys.iterator();
497         while ( it.hasNext() )
498         {
499             String key = (String) it.next();
500             Dependency parentDep = (Dependency) parentDepMap.get( key );
501             Dependency mainDep = (Dependency) mainDepMap.get( key );
502
503             if ( parentDep == null )
504             {
505                 // Means there is no parent depMan entry to override main depMan.
506                 merged.add( mainDep );
507             }
508             else
509             {
510                 // Parent depMan entry exists (main doesn't have to).
511                 // Merge the parent over the main depMan entry.
512                 merged.add( merge( mainDep, parentDep ) );
513             }
514         }
515
516         return merged;
517     }
518
519     public static List mergeExclusions( List mainExclusions, List parentExclusions )
520     {
521         if ( parentExclusions == null )
522         {
523             return mainExclusions;
524         }
525
526         if ( mainExclusions == null )
527         {
528             return ArchivaModelCloner.cloneExclusions( parentExclusions );
529         }
530
531         List merged = new ArrayList();
532
533         Map mainExclusionMap = createExclusionMap( mainExclusions );
534         Map parentExclusionMap = createExclusionMap( parentExclusions );
535
536         Iterator it = mainExclusionMap.entrySet().iterator();
537         while ( it.hasNext() )
538         {
539             Map.Entry entry = (Entry) it.next();
540             String key = (String) entry.getKey();
541             Exclusion mainExclusion = (Exclusion) entry.getValue();
542             Exclusion parentExclusion = (Exclusion) parentExclusionMap.get( key );
543
544             if ( parentExclusion == null )
545             {
546                 merged.add( mainExclusion );
547             }
548             else
549             {
550                 merged.add( parentExclusion );
551             }
552         }
553
554         return merged;
555     }
556
557     private static List mergeIndividuals( List mainIndividuals, List parentIndividuals )
558     {
559         if ( parentIndividuals == null )
560         {
561             return mainIndividuals;
562         }
563
564         if ( mainIndividuals == null )
565         {
566             return ArchivaModelCloner.cloneIndividuals( parentIndividuals );
567         }
568
569         List merged = ArchivaModelCloner.cloneIndividuals( mainIndividuals );
570
571         Iterator it = parentIndividuals.iterator();
572         while ( it.hasNext() )
573         {
574             Individual parentIndividual = (Individual) it.next();
575
576             if ( !mainIndividuals.contains( parentIndividual ) )
577             {
578                 merged.add( parentIndividual );
579             }
580         }
581
582         return merged;
583     }
584
585     private static List mergeLicenses( List mainLicenses, List parentLicenses )
586     {
587         if ( parentLicenses == null )
588         {
589             return mainLicenses;
590         }
591
592         if ( mainLicenses == null )
593         {
594             return ArchivaModelCloner.cloneLicenses( parentLicenses );
595         }
596
597         List merged = new ArrayList();
598
599         Map mainLicensesMap = createLicensesMap( mainLicenses );
600         Map parentLicensesMap = createLicensesMap( parentLicenses );
601
602         Iterator it = mainLicensesMap.entrySet().iterator();
603         while ( it.hasNext() )
604         {
605             Map.Entry entry = (Entry) it.next();
606             String key = (String) entry.getKey();
607             License mainLicense = (License) entry.getValue();
608             License parentLicense = (License) parentLicensesMap.get( key );
609
610             if ( parentLicense == null )
611             {
612                 merged.add( mainLicense );
613             }
614             else
615             {
616                 // Not merging. Local wins.
617                 merged.add( parentLicense );
618             }
619         }
620
621         return merged;
622     }
623
624     private static List mergePlugins( List mainPlugins, List parentPlugins )
625     {
626         return mergeArtifactReferences( mainPlugins, parentPlugins );
627     }
628
629     private static List mergeReports( List mainReports, List parentReports )
630     {
631         return mergeArtifactReferences( mainReports, parentReports );
632     }
633
634     private static List mergeRepositories( List mainRepositories, List parentRepositories )
635     {
636         if ( parentRepositories == null )
637         {
638             return mainRepositories;
639         }
640
641         if ( mainRepositories == null )
642         {
643             return ArchivaModelCloner.cloneLicenses( parentRepositories );
644         }
645
646         List merged = new ArrayList();
647
648         Map mainRepositoriesMap = createRepositoriesMap( mainRepositories );
649         Map parentRepositoriesMap = createRepositoriesMap( parentRepositories );
650
651         Iterator it = mainRepositoriesMap.entrySet().iterator();
652         while ( it.hasNext() )
653         {
654             Map.Entry entry = (Entry) it.next();
655             String key = (String) entry.getKey();
656             ProjectRepository mainProjectRepository = (ProjectRepository) entry.getValue();
657             ProjectRepository parentProjectRepository = (ProjectRepository) parentRepositoriesMap.get( key );
658
659             if ( parentProjectRepository == null )
660             {
661                 merged.add( mainProjectRepository );
662             }
663             else
664             {
665                 // Not merging. Local wins.
666                 merged.add( parentProjectRepository );
667             }
668         }
669
670         return merged;
671     }
672
673     private static String toVersionlessArtifactKey( ArtifactReference artifactReference )
674     {
675         StringBuffer key = new StringBuffer();
676
677         key.append( artifactReference.getGroupId() ).append( ":" ).append( artifactReference.getArtifactId() );
678         key.append( StringUtils.defaultString( artifactReference.getClassifier() ) ).append( ":" );
679         key.append( artifactReference.getType() );
680
681         return key.toString();
682     }
683
684     private static String toVersionlessDependencyKey( Dependency dep )
685     {
686         StringBuffer key = new StringBuffer();
687
688         key.append( dep.getGroupId() ).append( ":" ).append( dep.getArtifactId() );
689         key.append( StringUtils.defaultString( dep.getClassifier() ) ).append( ":" );
690         key.append( dep.getType() );
691
692         return key.toString();
693     }
694 }