View Javadoc

1   package org.apache.maven.continuum.core.action;
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.io.IOException;
23  import java.net.MalformedURLException;
24  import java.net.URISyntaxException;
25  import java.net.URL;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.maven.continuum.ContinuumException;
30  import org.apache.maven.continuum.execution.maven.m2.SettingsConfigurationException;
31  import org.apache.maven.continuum.model.project.BuildDefinitionTemplate;
32  import org.apache.maven.continuum.model.project.Project;
33  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilder;
34  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilderException;
35  import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
36  import org.apache.maven.continuum.project.builder.manager.ContinuumProjectBuilderManager;
37  import org.apache.maven.continuum.project.builder.manager.ContinuumProjectBuilderManagerException;
38  import org.apache.maven.continuum.utils.ContinuumUrlValidator;
39  import org.apache.maven.continuum.utils.URLUserInfo;
40  import org.apache.maven.settings.MavenSettingsBuilder;
41  import org.apache.maven.settings.Server;
42  import org.apache.maven.settings.Settings;
43  import org.codehaus.plexus.util.StringUtils;
44  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
45  
46  /**
47   * Resolve the project url being passed in and gather authentication information
48   * if the url is so configured, then create the projects
49   * <p/>
50   * Supports:
51   * <p/>
52   * - standard maven-scm url
53   * - MungedUrl https://username:password@host
54   * - maven settings based, server = host and scm info set to username and password
55   *
56   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
57   * @version $Id: CreateProjectsFromMetadataAction.java 816461 2009-09-18 03:54:50Z ctan $
58   * @plexus.component role="org.codehaus.plexus.action.Action"
59   * role-hint="create-projects-from-metadata"
60   */
61  public class CreateProjectsFromMetadataAction
62      extends AbstractContinuumAction
63  {
64      private static final String KEY_URL = "url";
65  
66      private static final String KEY_PROJECT_BUILDER_ID = "builderId";
67  
68      private static final String KEY_PROJECT_BUILDING_RESULT = "projectBuildingResult";
69  
70      private static final String KEY_LOAD_RECURSIVE_PROJECTS = "loadRecursiveProjects";
71  
72      /**
73       * @plexus.requirement
74       */
75      private ContinuumProjectBuilderManager projectBuilderManager;
76  
77      /**
78       * @plexus.requirement
79       */
80      private MavenSettingsBuilder mavenSettingsBuilder;
81  
82      /**
83       * @plexus.requirement role-hint="continuumUrl"
84       */
85      private ContinuumUrlValidator urlValidator;
86  
87      public void execute( Map context )
88          throws ContinuumException, ContinuumProjectBuilderManagerException, ContinuumProjectBuilderException
89      {
90          String projectBuilderId = getProjectBuilderId( context );
91  
92          boolean loadRecursiveProjects = isLoadRecursiveProject( context );
93  
94          String curl = getUrl( context );
95  
96          URL url;
97  
98          ContinuumProjectBuilder projectBuilder = projectBuilderManager.getProjectBuilder( projectBuilderId );
99  
100         ContinuumProjectBuildingResult result;
101 
102         try
103         {
104             BuildDefinitionTemplate buildDefinitionTemplate = getBuildDefinitionTemplate( context );
105             if ( buildDefinitionTemplate == null )
106             {
107                 buildDefinitionTemplate = projectBuilder.getDefaultBuildDefinitionTemplate();
108             }
109             if ( !curl.startsWith( "http" ) )
110             {
111                 url = new URL( curl );
112 
113                 result = projectBuilder.buildProjectsFromMetadata( url, null, null, loadRecursiveProjects,
114                                                                    buildDefinitionTemplate );
115 
116             }
117             else
118             {
119                 url = new URL( curl );
120                 String username = null;
121                 String password = null;
122 
123                 try
124                 {
125                     Settings settings = getSettings();
126 
127                     getLogger().info( "checking for settings auth setup" );
128                     if ( settings != null && settings.getServer( url.getHost() ) != null )
129                     {
130                         getLogger().info( "found setting based auth setup, using" );
131                         Server server = settings.getServer( url.getHost() );
132 
133                         username = server.getUsername();
134                         password = server.getPassword();
135                     }
136                 }
137                 catch ( SettingsConfigurationException se )
138                 {
139                     getLogger().warn( "problem with settings file, disabling scm resolution of username and password" );
140                 }
141 
142                 if ( username == null )
143                 {
144                     URLUserInfo urlUserInfo = urlValidator.extractURLUserInfo( curl );
145                     username = urlUserInfo.getUsername();
146                     password = urlUserInfo.getPassword();
147                 }
148 
149                 if ( urlValidator.isValid( curl ) )
150                 {
151 
152                     result = projectBuilder.buildProjectsFromMetadata( url, username, password, loadRecursiveProjects,
153                                                                        buildDefinitionTemplate );
154 
155                 }
156                 else
157                 {
158                     result = new ContinuumProjectBuildingResult();
159                     getLogger().info( "Malformed URL (MungedHttpsURL is not valid): " + hidePasswordInUrl( curl ) );
160                     result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
161                 }
162             }
163 
164             if ( result.getProjects() != null )
165             {
166                 String scmRootUrl = getScmRootUrl( result.getProjects() );
167 
168                 if ( scmRootUrl == null || scmRootUrl.equals( "" ) )
169                 {
170                     if ( curl.indexOf( "pom.xml" ) > 0 )
171                     {
172                         scmRootUrl = curl.substring( 0, curl.indexOf( "pom.xml" ) - 1 );
173                     }
174                     else
175                     {
176                         scmRootUrl = curl;
177                     }
178                 }
179 
180                 setUrl( context, scmRootUrl );
181             }
182         }
183         catch ( MalformedURLException e )
184         {
185             getLogger().info( "Malformed URL: " + hidePasswordInUrl( curl ), e );
186             result = new ContinuumProjectBuildingResult();
187             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
188         }
189         catch ( URISyntaxException e )
190         {
191             getLogger().info( "Malformed URL: " + hidePasswordInUrl( curl ), e );
192             result = new ContinuumProjectBuildingResult();
193             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
194         }
195 
196         setProjectBuildingResult( context, result );
197     }
198 
199     private String hidePasswordInUrl( String url )
200     {
201         int indexAt = url.indexOf( "@" );
202 
203         if ( indexAt < 0 )
204         {
205             return url;
206         }
207 
208         String s = url.substring( 0, indexAt );
209 
210         int pos = s.lastIndexOf( ":" );
211 
212         return s.substring( 0, pos + 1 ) + "*****" + url.substring( indexAt );
213     }
214 
215     private Settings getSettings()
216         throws SettingsConfigurationException
217     {
218         try
219         {
220             return mavenSettingsBuilder.buildSettings();
221         }
222         catch ( IOException e )
223         {
224             throw new SettingsConfigurationException( "Error reading settings file", e );
225         }
226         catch ( XmlPullParserException e )
227         {
228             throw new SettingsConfigurationException( e.getMessage(), e.getDetail(), e.getLineNumber(),
229                                                       e.getColumnNumber() );
230         }
231     }
232 
233     private String getScmRootUrl( List<Project> projects )
234     {
235         String scmRootUrl = "";
236 
237         for ( Project project : projects )
238         {
239             String scmUrl = project.getScmUrl();
240 
241             scmRootUrl = getCommonPath( scmUrl, scmRootUrl );
242         }
243 
244         return scmRootUrl;
245     }
246 
247     private String getCommonPath( String path1, String path2 )
248     {
249         if ( path2 == null || path2.equals( "" ) )
250         {
251             return path1;
252         }
253         else
254         {
255             int indexDiff = StringUtils.differenceAt( path1, path2 );
256             String commonPath = path1.substring( 0, indexDiff );
257 
258             if ( commonPath.lastIndexOf( '/' ) != commonPath.length() - 1 &&
259                  !( path1.contains( new String( commonPath + "/" ) ) || 
260                     path2.contains( new String( commonPath + "/" ) ) ) )
261             {
262                 while ( commonPath.lastIndexOf( '/' ) != commonPath.length() - 1 )
263                 {
264                     commonPath = commonPath.substring( 0, commonPath.length() - 1 );
265                 }
266             }
267 
268             return commonPath;
269         }
270     }
271 
272     public ContinuumProjectBuilderManager getProjectBuilderManager()
273     {
274         return projectBuilderManager;
275     }
276 
277     public void setProjectBuilderManager( ContinuumProjectBuilderManager projectBuilderManager )
278     {
279         this.projectBuilderManager = projectBuilderManager;
280     }
281 
282     public MavenSettingsBuilder getMavenSettingsBuilder()
283     {
284         return mavenSettingsBuilder;
285     }
286 
287     public void setMavenSettingsBuilder( MavenSettingsBuilder mavenSettingsBuilder )
288     {
289         this.mavenSettingsBuilder = mavenSettingsBuilder;
290     }
291 
292     public ContinuumUrlValidator getUrlValidator()
293     {
294         return urlValidator;
295     }
296 
297     public void setUrlValidator( ContinuumUrlValidator urlValidator )
298     {
299         this.urlValidator = urlValidator;
300     }
301 
302     public static ContinuumProjectBuildingResult getProjectBuildingResult( Map<String, Object> context )
303     {
304         return (ContinuumProjectBuildingResult) getObject( context, KEY_PROJECT_BUILDING_RESULT );
305     }
306 
307     private static void setProjectBuildingResult( Map<String, Object> context, ContinuumProjectBuildingResult result )
308     {
309         context.put( KEY_PROJECT_BUILDING_RESULT, result );
310     }
311 
312     public static String getUrl( Map<String, Object> context )
313     {
314         return getString( context, KEY_URL );
315     }
316 
317     public static void setUrl( Map<String, Object> context, String url )
318     {
319         context.put( KEY_URL, url );
320     }
321 
322     public static String getProjectBuilderId( Map<String, Object> context )
323     {
324         return getString( context, KEY_PROJECT_BUILDER_ID );
325     }
326 
327     public static void setProjectBuilderId( Map<String, Object> context, String projectBuilderId )
328     {
329         context.put( KEY_PROJECT_BUILDER_ID, projectBuilderId );
330     }
331 
332     public static boolean isLoadRecursiveProject( Map<String, Object> context )
333     {
334         return getBoolean( context, KEY_LOAD_RECURSIVE_PROJECTS );
335     }
336 
337     public static void setLoadRecursiveProject( Map<String, Object> context, boolean loadRecursiveProject )
338     {
339         context.put( KEY_LOAD_RECURSIVE_PROJECTS, loadRecursiveProject );
340     }
341 }