View Javadoc

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.collections.CollectionUtils;
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.maven.archiva.model.ArchivaModelCloner;
25  import org.apache.maven.archiva.model.ArchivaProjectModel;
26  import org.apache.maven.archiva.model.ArtifactReference;
27  import org.apache.maven.archiva.model.CiManagement;
28  import org.apache.maven.archiva.model.Dependency;
29  import org.apache.maven.archiva.model.Exclusion;
30  import org.apache.maven.archiva.model.Individual;
31  import org.apache.maven.archiva.model.IssueManagement;
32  import org.apache.maven.archiva.model.License;
33  import org.apache.maven.archiva.model.MailingList;
34  import org.apache.maven.archiva.model.Organization;
35  import org.apache.maven.archiva.model.ProjectRepository;
36  import org.apache.maven.archiva.model.Scm;
37  import org.apache.maven.archiva.model.VersionedReference;
38  import org.apache.maven.archiva.repository.project.ProjectModelException;
39  import org.apache.maven.archiva.repository.project.ProjectModelFilter;
40  import org.codehaus.plexus.evaluator.DefaultExpressionEvaluator;
41  import org.codehaus.plexus.evaluator.EvaluatorException;
42  import org.codehaus.plexus.evaluator.ExpressionEvaluator;
43  import org.codehaus.plexus.evaluator.ExpressionSource;
44  import org.codehaus.plexus.evaluator.sources.PropertiesExpressionSource;
45  import org.codehaus.plexus.evaluator.sources.SystemPropertyExpressionSource;
46  
47  import java.util.ArrayList;
48  import java.util.HashSet;
49  import java.util.List;
50  import java.util.Properties;
51  import java.util.Set;
52  
53  /**
54   * ProjectModelExpressionFilter 
55   *
56   * @version $Id: ProjectModelExpressionFilter.java 778118 2009-05-24 10:58:49Z oching $
57   * @plexus.component role="org.apache.maven.archiva.repository.project.ProjectModelFilter"
58   *                   role-hint="expression" 
59   *                   instantiation-strategy="per-lookup"
60   */
61  public class ProjectModelExpressionFilter
62      implements ProjectModelFilter
63  {
64      private ExpressionEvaluator evaluator = new DefaultExpressionEvaluator();
65  
66      /**
67       * Find and Evaluate the Expressions present in the model.
68       * 
69       * @param model the model to correct.
70       */
71      @SuppressWarnings("unchecked")
72      public ArchivaProjectModel filter( final ArchivaProjectModel model )
73          throws ProjectModelException
74      {
75          Properties props = new Properties();
76  
77          if ( model.getProperties() != null )
78          {
79              props.putAll( model.getProperties() );
80          }
81  
82          ArchivaProjectModel ret = ArchivaModelCloner.clone( model );
83  
84          // TODO: should probably clone evaluator to prevent threading issues.
85          synchronized ( evaluator )
86          {
87              // TODO: create .resetSources() method in ExpressionEvaluator project on plexus side.
88              // Remove previous expression sources.
89              List<ExpressionSource> oldSources = new ArrayList<ExpressionSource>();
90              oldSources.addAll( evaluator.getExpressionSourceList() );
91              for ( ExpressionSource exprSrc : oldSources )
92              {
93                  evaluator.removeExpressionSource( exprSrc );
94              }
95  
96              // Setup new sources (based on current model)
97              PropertiesExpressionSource propsSource = new PropertiesExpressionSource();
98              propsSource.setProperties( props );
99              evaluator.addExpressionSource( propsSource );
100 
101             // Add system properties to the mix. 
102             evaluator.addExpressionSource( new SystemPropertyExpressionSource() );
103 
104             try
105             {
106                 // Setup some common properties.
107                 VersionedReference parent = model.getParentProject();
108                 if ( parent != null )
109                 {
110                     String parentGroupId = StringUtils.defaultString( evaluator.expand( parent.getGroupId() ) );
111                     String parentArtifactId = StringUtils.defaultString( evaluator.expand( parent.getArtifactId() ) );
112                     String parentVersion = StringUtils.defaultString( evaluator.expand( parent.getVersion() ) );
113 
114                     props.setProperty( "parent.groupId", parentGroupId );
115                     props.setProperty( "parent.artifactId", parentArtifactId );
116                     props.setProperty( "parent.version", parentVersion );
117                 }
118 
119                 String groupId = StringUtils.defaultString( evaluator.expand( model.getGroupId() ) );
120                 String artifactId = StringUtils.defaultString( evaluator.expand( model.getArtifactId() ) );
121                 String version = StringUtils.defaultString( evaluator.expand( model.getVersion() ) );
122                 String name = StringUtils.defaultString( evaluator.expand( model.getName() ) );
123                 
124 
125                 /* Archiva doesn't need to handle a full expression language with object tree walking
126                  * as the requirements within Archiva are much smaller, a quick replacement of the
127                  * important fields (groupId, artifactId, version, name) are handled specifically. 
128                  */
129                 props.setProperty( "pom.groupId",  groupId );
130                 props.setProperty( "pom.artifactId", artifactId );
131                 props.setProperty( "pom.version", version );
132                 props.setProperty( "pom.name", name );
133                 props.setProperty( "project.groupId",  groupId );
134                 props.setProperty( "project.artifactId", artifactId );
135                 props.setProperty( "project.version", version );
136                 props.setProperty( "project.name", name );
137 
138                 // Evaluate everything.
139                 ret.setVersion( evaluator.expand( ret.getVersion() ) );
140                 ret.setGroupId( evaluator.expand( ret.getGroupId() ) );
141                 ret.setName( evaluator.expand( ret.getName() ) );
142                 ret.setDescription( evaluator.expand( ret.getDescription() ) );
143                 ret.setPackaging( evaluator.expand( ret.getPackaging() ) );
144                 ret.setUrl( evaluator.expand( ret.getUrl() ) );
145 
146                 evaluateParentProject( evaluator, ret.getParentProject() );
147 
148                 evaluateBuildExtensions( evaluator, ret.getBuildExtensions() );
149                 evaluateCiManagement( evaluator, ret.getCiManagement() );
150                 evaluateDependencyList( evaluator, ret.getDependencies() );
151                 evaluateDependencyList( evaluator, ret.getDependencyManagement() );
152                 evaluateIndividuals( evaluator, ret.getIndividuals() );
153                 evaluateIssueManagement( evaluator, ret.getIssueManagement() );
154                 evaluateLicenses( evaluator, ret.getLicenses() );
155                 evaluateMailingLists( evaluator, ret.getMailingLists() );
156                 evaluateOrganization( evaluator, ret.getOrganization() );
157                 evaluatePlugins( evaluator, ret.getPlugins() );
158                 evaluateRelocation( evaluator, ret.getRelocation() );
159                 evaluateReports( evaluator, ret.getReports() );
160                 evaluateRepositories( evaluator, ret.getRepositories() );
161                 evaluateScm( evaluator, ret.getScm() );
162             }
163             catch ( EvaluatorException e )
164             {
165                 throw new ProjectModelException( "Unable to evaluate expression in model: " + e.getMessage(), e );
166             }
167         }
168 
169         return ret;
170     }
171 
172     private void evaluateArtifactReferenceList( ExpressionEvaluator eval, List<ArtifactReference> refs )
173         throws EvaluatorException
174     {
175         if ( CollectionUtils.isEmpty( refs ) )
176         {
177             return;
178         }
179 
180         for ( ArtifactReference ref : refs )
181         {
182             ref.setGroupId( eval.expand( ref.getGroupId() ) );
183             ref.setArtifactId( eval.expand( ref.getArtifactId() ) );
184             ref.setVersion( eval.expand( ref.getVersion() ) );
185             ref.setClassifier( eval.expand( ref.getClassifier() ) );
186             ref.setType( eval.expand( ref.getType() ) );
187         }
188     }
189 
190     private void evaluateBuildExtensions( ExpressionEvaluator eval, List<ArtifactReference> buildExtensions )
191         throws EvaluatorException
192     {
193         if ( CollectionUtils.isEmpty( buildExtensions ) )
194         {
195             return;
196         }
197 
198         for ( ArtifactReference ref : buildExtensions )
199         {
200             ref.setGroupId( eval.expand( ref.getGroupId() ) );
201             ref.setArtifactId( eval.expand( ref.getArtifactId() ) );
202             ref.setVersion( eval.expand( ref.getVersion() ) );
203             ref.setClassifier( eval.expand( ref.getClassifier() ) );
204             ref.setType( eval.expand( ref.getType() ) );
205         }
206     }
207 
208     private void evaluateCiManagement( ExpressionEvaluator eval, CiManagement ciManagement )
209         throws EvaluatorException
210     {
211         if ( ciManagement == null )
212         {
213             return;
214         }
215 
216         ciManagement.setSystem( eval.expand( ciManagement.getSystem() ) );
217         ciManagement.setUrl( eval.expand( ciManagement.getUrl() ) );
218         ciManagement.setCiUrl( eval.expand( ciManagement.getCiUrl() ) );
219     }
220 
221     private void evaluateDependencyList( ExpressionEvaluator eval, List<Dependency> dependencies )
222         throws EvaluatorException
223     {
224         if ( CollectionUtils.isEmpty( dependencies ) )
225         {
226             return;
227         }
228 
229         for ( Dependency dependency : dependencies )
230         {
231             dependency.setGroupId( eval.expand( dependency.getGroupId() ) );
232             dependency.setArtifactId( eval.expand( dependency.getArtifactId() ) );
233             dependency.setVersion( eval.expand( dependency.getVersion() ) );
234             dependency.setScope( eval.expand( dependency.getScope() ) );
235             dependency.setType( eval.expand( dependency.getType() ) );
236             dependency.setUrl( eval.expand( dependency.getUrl() ) );
237 
238             evaluateExclusions( eval, dependency.getExclusions() );
239         }
240     }
241 
242     private void evaluateExclusions( ExpressionEvaluator eval, List<Exclusion> exclusions )
243         throws EvaluatorException
244     {
245         if ( CollectionUtils.isEmpty( exclusions ) )
246         {
247             return;
248         }
249 
250         for ( Exclusion exclusion : exclusions )
251         {
252             exclusion.setGroupId( eval.expand( exclusion.getGroupId() ) );
253             exclusion.setArtifactId( eval.expand( exclusion.getArtifactId() ) );
254         }
255     }
256 
257     private void evaluateIndividuals( ExpressionEvaluator eval, List<Individual> individuals )
258         throws EvaluatorException
259     {
260         if ( CollectionUtils.isEmpty( individuals ) )
261         {
262             return;
263         }
264 
265         for ( Individual individual : individuals )
266         {
267             individual.setPrincipal( eval.expand( individual.getPrincipal() ) );
268             individual.setName( eval.expand( individual.getName() ) );
269             individual.setEmail( eval.expand( individual.getEmail() ) );
270             individual.setTimezone( eval.expand( individual.getTimezone() ) );
271             individual.setOrganization( eval.expand( individual.getOrganization() ) );
272             individual.setOrganizationUrl( eval.expand( individual.getOrganizationUrl() ) );
273             individual.setUrl( eval.expand( individual.getUrl() ) );
274             individual.setIndividualEmail( eval.expand( individual.getIndividualEmail() ) );
275 
276             evaluateProperties( eval, individual.getProperties() );
277             evaluateStringList( eval, individual.getRoles() );
278         }
279     }
280 
281     private void evaluateIssueManagement( ExpressionEvaluator eval, IssueManagement issueManagement )
282         throws EvaluatorException
283     {
284         if ( issueManagement == null )
285         {
286             return;
287         }
288 
289         issueManagement.setSystem( eval.expand( issueManagement.getSystem() ) );
290         issueManagement.setUrl( eval.expand( issueManagement.getUrl() ) );
291         issueManagement.setIssueManagementUrl( eval.expand( issueManagement.getIssueManagementUrl() ) );
292     }
293 
294     private void evaluateLicenses( ExpressionEvaluator eval, List<License> licenses )
295         throws EvaluatorException
296     {
297         if ( CollectionUtils.isEmpty( licenses ) )
298         {
299             return;
300         }
301 
302         for ( License license : licenses )
303         {
304             license.setName( eval.expand( license.getName() ) );
305             license.setUrl( eval.expand( license.getUrl() ) );
306             license.setComments( eval.expand( license.getComments() ) );
307         }
308     }
309 
310     private void evaluateMailingLists( ExpressionEvaluator eval, List<MailingList> mailingLists )
311         throws EvaluatorException
312     {
313         if ( CollectionUtils.isEmpty( mailingLists ) )
314         {
315             return;
316         }
317 
318         for ( MailingList mlist : mailingLists )
319         {
320             mlist.setName( eval.expand( mlist.getName() ) );
321             mlist.setSubscribeAddress( eval.expand( mlist.getSubscribeAddress() ) );
322             mlist.setUnsubscribeAddress( eval.expand( mlist.getUnsubscribeAddress() ) );
323             mlist.setPostAddress( eval.expand( mlist.getPostAddress() ) );
324             mlist.setMainArchiveUrl( eval.expand( mlist.getMainArchiveUrl() ) );
325 
326             evaluateStringList( eval, mlist.getOtherArchives() );
327         }
328     }
329 
330     private void evaluateOrganization( ExpressionEvaluator eval, Organization organization )
331         throws EvaluatorException
332     {
333         if ( organization == null )
334         {
335             return;
336         }
337 
338         organization.setOrganizationName( eval.expand( organization.getOrganizationName() ) );
339         organization.setName( eval.expand( organization.getName() ) );
340         organization.setUrl( eval.expand( organization.getUrl() ) );
341         organization.setFavicon( eval.expand( organization.getFavicon() ) );
342     }
343 
344     private void evaluateParentProject( ExpressionEvaluator eval, VersionedReference parentProject )
345         throws EvaluatorException
346     {
347         if ( parentProject == null )
348         {
349             return;
350         }
351 
352         parentProject.setGroupId( eval.expand( parentProject.getGroupId() ) );
353         parentProject.setArtifactId( eval.expand( parentProject.getArtifactId() ) );
354         parentProject.setVersion( eval.expand( parentProject.getVersion() ) );
355     }
356 
357     private void evaluatePlugins( ExpressionEvaluator eval, List<ArtifactReference> plugins )
358         throws EvaluatorException
359     {
360         evaluateArtifactReferenceList( eval, plugins );
361     }
362 
363     private void evaluateProperties( ExpressionEvaluator eval, Properties props )
364         throws EvaluatorException
365     {
366         if ( props == null )
367         {
368             return;
369         }
370 
371         // Only evaluate the values, not the keys.
372 
373         // Collect the key names. (Done ahead of time to prevent iteration / concurrent modification exceptions)
374         Set<String> keys = new HashSet<String>();
375         for ( Object obj : props.keySet() )
376         {
377             keys.add( (String) obj );
378         }
379 
380         // Evaluate all of the values.
381         for ( String key : keys )
382         {
383             String value = props.getProperty( key );
384             props.setProperty( key, eval.expand( value ) );
385         }
386     }
387 
388     private void evaluateRelocation( ExpressionEvaluator eval, VersionedReference relocation )
389         throws EvaluatorException
390     {
391         if ( relocation == null )
392         {
393             return;
394         }
395 
396         relocation.setGroupId( eval.expand( relocation.getGroupId() ) );
397         relocation.setArtifactId( eval.expand( relocation.getArtifactId() ) );
398         relocation.setVersion( eval.expand( relocation.getVersion() ) );
399     }
400 
401     private void evaluateReports( ExpressionEvaluator eval, List<ArtifactReference> reports )
402         throws EvaluatorException
403     {
404         evaluateArtifactReferenceList( eval, reports );
405     }
406 
407     private void evaluateRepositories( ExpressionEvaluator eval, List<ProjectRepository> repositories )
408         throws EvaluatorException
409     {
410         if ( CollectionUtils.isEmpty( repositories ) )
411         {
412             return;
413         }
414 
415         for ( ProjectRepository repository : repositories )
416         {
417             repository.setId( eval.expand( repository.getId() ) );
418             repository.setLayout( eval.expand( repository.getLayout() ) );
419             repository.setName( eval.expand( repository.getName() ) );
420             repository.setUrl( eval.expand( repository.getUrl() ) );
421         }
422     }
423 
424     private void evaluateScm( ExpressionEvaluator eval, Scm scm )
425         throws EvaluatorException
426     {
427         if ( scm == null )
428         {
429             return;
430         }
431 
432         scm.setConnection( eval.expand( scm.getConnection() ) );
433         scm.setDeveloperConnection( eval.expand( scm.getDeveloperConnection() ) );
434         scm.setUrl( eval.expand( scm.getUrl() ) );
435     }
436 
437     private void evaluateStringList( ExpressionEvaluator eval, List<String> strings )
438         throws EvaluatorException
439     {
440         if ( CollectionUtils.isEmpty( strings ) )
441         {
442             return;
443         }
444 
445         // Create new list to hold post-evaluated strings.
446         List<String> evaluated = new ArrayList<String>();
447 
448         // Evaluate them all
449         for ( String str : strings )
450         {
451             evaluated.add( eval.expand( str ) );
452         }
453 
454         // Populate the original list with the post-evaluated list.
455         strings.clear();
456         strings.addAll( evaluated );
457     }
458 }