]> source.dussan.org Git - archiva.git/blob
33083768bf71688af01d2dcf916ffcca9c6f9259
[archiva.git] /
1 package org.apache.maven.archiva.repository.project.filters;
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.Dependency;
26 import org.apache.maven.archiva.model.VersionedReference;
27 import org.apache.maven.archiva.repository.project.ProjectModelException;
28 import org.apache.maven.archiva.repository.project.ProjectModelFilter;
29 import org.apache.maven.archiva.repository.project.ProjectModelMerge;
30 import org.apache.maven.archiva.repository.project.ProjectModelResolver;
31
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37
38 /**
39  * Builder for the Effective Project Model.  
40  *
41  * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
42  * @version $Id$
43  * @plexus.component role="org.apache.maven.archiva.repository.project.ProjectModelFilter" 
44  *                   role-hint="effective" 
45  *                   instantiation-strategy="per-lookup"
46  */
47 public class EffectiveProjectModelFilter implements ProjectModelFilter
48 {
49     /**
50      * @plexus.requirement role-hint="expression"
51      */
52     private ProjectModelFilter expressionFilter;
53     
54     private List projectModelResolvers;
55     
56     public EffectiveProjectModelFilter()
57     {
58         projectModelResolvers = new ArrayList();
59     }
60
61     public void addProjectModelResolver( ProjectModelResolver resolver )
62     {
63         if ( resolver == null )
64         {
65             return;
66         }
67
68         this.projectModelResolvers.add( resolver );
69     }
70
71     /**
72      * Take the provided {@link ArchivaProjectModel} and build the effective {@link ArchivaProjectModel}.
73      * 
74      * Steps:
75      * 1) Expand any expressions / properties.
76      * 2) Walk the parent project references and merge.
77      * 3) Apply dependency management settings.
78      * 
79      * @param project the project to create the effective {@link ArchivaProjectModel} from.
80      * @return a the effective {@link ArchivaProjectModel}.
81      * @throws ProjectModelException if there was a problem building the effective pom.
82      */
83     public ArchivaProjectModel filter( final ArchivaProjectModel project )
84         throws ProjectModelException
85     {
86         if ( project == null )
87         {
88             return null;
89         }
90
91         if ( this.projectModelResolvers.isEmpty() )
92         {
93             throw new IllegalStateException( "Unable to build effective pom with no project model resolvers defined." );
94         }
95
96         // Clone submitted project (so that we don't mess with it) 
97         ArchivaProjectModel effectiveProject = ArchivaModelCloner.clone( project );
98
99         // Setup Expression Evaluation pieces.
100         effectiveProject = expressionFilter.filter( effectiveProject );
101
102         debug( "Starting build of effective with: " + effectiveProject );
103
104         // Merge in all the parent poms.
105         effectiveProject = mergeParent( effectiveProject );
106
107         // Resolve dependency versions from dependency management.
108         applyDependencyManagement( effectiveProject );
109
110         // Return what we got.
111         return effectiveProject;
112     }
113
114     public void removeResolver( ProjectModelResolver resolver )
115     {
116         this.projectModelResolvers.remove( resolver );
117     }
118
119     private void applyDependencyManagement( ArchivaProjectModel pom )
120     {
121         if ( ( pom.getDependencyManagement() == null ) || ( pom.getDependencies() == null ) )
122         {
123             // Nothing to do. All done!
124             return;
125         }
126         
127         if ( pom.getDependencyManagement().isEmpty() || pom.getDependencies().isEmpty() )
128         {
129             // Nothing to do. All done!
130             return;
131         }
132
133         Map managedDependencies = createDependencyMap( pom.getDependencyManagement() );
134         Iterator it = pom.getDependencies().iterator();
135         while ( it.hasNext() )
136         {
137             Dependency dep = (Dependency) it.next();
138             String key = toVersionlessDependencyKey( dep );
139
140             // Do we need to do anything?
141             if ( managedDependencies.containsKey( key ) )
142             {
143                 Dependency mgmtDep = (Dependency) managedDependencies.get( key );
144
145                 dep.setVersion( mgmtDep.getVersion() );
146                 dep.setScope( mgmtDep.getScope() );
147                 dep.setExclusions( ProjectModelMerge.mergeExclusions( dep.getExclusions(), mgmtDep.getExclusions() ) );
148             }
149         }
150     }
151
152     private void debug( String msg )
153     {
154         System.out.println( "## " + msg );
155     }
156
157     private ArchivaProjectModel findProject( VersionedReference projectRef )
158     {
159         debug( "Trying to find project: " + projectRef );
160         Iterator it = this.projectModelResolvers.iterator();
161
162         while ( it.hasNext() )
163         {
164             ProjectModelResolver resolver = (ProjectModelResolver) it.next();
165
166             try
167             {
168                 debug( "Trying to find in " + resolver.getClass().getName() );
169                 ArchivaProjectModel model = resolver.resolveProjectModel( projectRef );
170
171                 if ( model != null )
172                 {
173                     debug( "Found it!: " + model );
174                     return model;
175                 }
176                 debug( "Not found." );
177             }
178             catch ( ProjectModelException e )
179             {
180                 // TODO: trigger notifier of problem?
181                 e.printStackTrace();
182             }
183         }
184
185         // TODO: Document that project was not found. (Use monitor?)
186
187         return null;
188     }
189
190     private ArchivaProjectModel mergeParent( ArchivaProjectModel pom )
191         throws ProjectModelException
192     {
193         ArchivaProjectModel mixedProject;
194
195         debug( "Parent: " + pom.getParentProject() );
196
197         if ( pom.getParentProject() != null )
198         {
199             // Use parent reference.
200             VersionedReference parentRef = pom.getParentProject();
201
202             debug( "Has parent: " + parentRef );
203
204             // Find parent using resolvers.
205             ArchivaProjectModel parentProject = findProject( parentRef );
206
207             if ( parentProject != null )
208             {
209                 parentProject = expressionFilter.filter( parentProject );
210                 parentProject = mergeParent( parentProject );
211                 mixedProject = ProjectModelMerge.merge( pom, parentProject );
212             }
213             else
214             {
215                 // Shortcircuit due to missing parent pom.
216                 // TODO: Document this via monitor.
217                 mixedProject = mixinSuperPom( pom );
218             }
219         }
220         else
221         {
222             debug( "No parent found" );
223
224             /* Mix in the super-pom.
225              * 
226              * Super POM from maven/components contains many things.
227              * However, for purposes of archiva, only the <repositories>
228              * and <pluginRepositories> sections are of any value.
229              */
230
231             mixedProject = mixinSuperPom( pom );
232         }
233
234         return mixedProject;
235     }
236
237     /**
238      * Super POM from maven/components contains many things.
239      * However, for purposes of archiva, only the <repositories>
240      * and <pluginRepositories> sections are of any value.
241      * 
242      * @param pom
243      * @return
244      */
245     private ArchivaProjectModel mixinSuperPom( ArchivaProjectModel pom )
246     {
247         // TODO: add super pom repositories.
248         debug( "Mix in Super POM: " + pom );
249
250         return pom;
251     }
252
253     private static Map createDependencyMap( List dependencies )
254     {
255         Map ret = new HashMap();
256
257         Iterator it = dependencies.iterator();
258         while ( it.hasNext() )
259         {
260             Dependency dep = (Dependency) it.next();
261             String key = toVersionlessDependencyKey( dep );
262             ret.put( key, dep );
263         }
264
265         return ret;
266     }
267
268     private static String toVersionlessDependencyKey( Dependency dep )
269     {
270         StringBuffer key = new StringBuffer();
271
272         key.append( dep.getGroupId() ).append( ":" ).append( dep.getArtifactId() );
273         key.append( StringUtils.defaultString( dep.getClassifier() ) ).append( ":" );
274         key.append( dep.getType() );
275
276         return key.toString();
277     }
278 }