View Javadoc

1   package org.apache.maven.continuum.web.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 com.opensymphony.xwork2.ActionContext;
23  import com.opensymphony.xwork2.config.ConfigurationManager;
24  import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
25  import com.opensymphony.xwork2.inject.Container;
26  import com.opensymphony.xwork2.util.ValueStack;
27  import com.opensymphony.xwork2.util.ValueStackFactory;
28  import org.apache.commons.io.FileUtils;
29  import org.apache.maven.continuum.ContinuumException;
30  import org.apache.maven.continuum.builddefinition.BuildDefinitionServiceException;
31  import org.apache.maven.continuum.model.project.BuildDefinitionTemplate;
32  import org.apache.maven.continuum.model.project.ProjectGroup;
33  import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
34  import org.apache.maven.continuum.web.exception.AuthorizationRequiredException;
35  import org.apache.struts2.interceptor.ServletRequestAware;
36  import org.codehaus.plexus.util.StringUtils;
37  
38  import java.io.File;
39  import java.io.IOException;
40  import java.io.UnsupportedEncodingException;
41  import java.net.MalformedURLException;
42  import java.net.URL;
43  import java.net.URLEncoder;
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import java.util.List;
47  import javax.servlet.http.HttpServletRequest;
48  
49  /**
50   * Action to add a Maven project to Continuum, either Maven 1 or Maven 2.
51   *
52   * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
53   * @version $Id: AddMavenProjectAction.java 1372260 2012-08-13 04:29:09Z brett $
54   */
55  public abstract class AddMavenProjectAction
56      extends ContinuumActionSupport
57      implements ServletRequestAware
58  {
59      private static final long serialVersionUID = -3965565189557706469L;
60  
61      private static final int DEFINED_BY_POM_GROUP_ID = -1;
62  
63      private String pomUrl;
64  
65      private File pomFile;
66  
67      private String pom = null;
68  
69      private String scmUsername;
70  
71      private String scmPassword;
72  
73      private Collection<ProjectGroup> projectGroups;
74  
75      private String projectGroupName;
76  
77      private int selectedProjectGroup = DEFINED_BY_POM_GROUP_ID;
78  
79      private boolean disableGroupSelection;
80  
81      private boolean scmUseCache;
82  
83      private int projectGroupId;
84  
85      private List<BuildDefinitionTemplate> buildDefinitionTemplates;
86  
87      private int buildDefinitionTemplateId;
88  
89      private List<String> errorMessages = new ArrayList<String>();
90  
91      private HttpServletRequest httpServletRequest;
92  
93      public String execute()
94          throws ContinuumException, BuildDefinitionServiceException
95      {
96          try
97          {
98              initializeProjectGroupName();
99  
100             if ( StringUtils.isEmpty( getProjectGroupName() ) )
101             {
102                 checkAddProjectGroupAuthorization();
103             }
104             else
105             {
106                 checkAddProjectToGroupAuthorization( getProjectGroupName() );
107             }
108         }
109         catch ( AuthorizationRequiredException authzE )
110         {
111             addActionError( authzE.getMessage() );
112             return REQUIRES_AUTHORIZATION;
113         }
114 
115         // ctan: hack for WW-3161
116         if ( ActionContext.getContext() == null )
117         {
118             // This fix allow initialization of ActionContext.getContext() to avoid NPE
119 
120             ConfigurationManager configurationManager = new ConfigurationManager();
121             configurationManager.addContainerProvider( new XWorkConfigurationProvider() );
122             com.opensymphony.xwork2.config.Configuration config = configurationManager.getConfiguration();
123             Container container = config.getContainer();
124 
125             ValueStack stack = container.getInstance( ValueStackFactory.class ).createValueStack();
126             stack.getContext().put( ActionContext.CONTAINER, container );
127             ActionContext.setContext( new ActionContext( stack.getContext() ) );
128         }
129 
130         boolean checkProtocol = true;
131 
132         if ( !StringUtils.isEmpty( pomUrl ) )
133         {
134             try
135             {
136                 URL url = new URL( pomUrl );
137                 if ( pomUrl.startsWith( "http" ) && !StringUtils.isEmpty( scmUsername ) )
138                 {
139                     String encoding = this.httpServletRequest.getCharacterEncoding();
140                     if ( StringUtils.isEmpty( encoding ) )
141                     {
142                         encoding = System.getProperty( "file.encoding" );
143                     }
144 
145                     String encodedUsername = URLEncoder.encode( scmUsername, encoding );
146                     String encodedPassword = URLEncoder.encode( scmPassword, encoding );
147 
148                     StringBuffer urlBuffer = new StringBuffer();
149                     urlBuffer.append( url.getProtocol() ).append( "://" );
150                     urlBuffer.append( encodedUsername ).append( ':' ).append( encodedPassword ).append( '@' ).append(
151                         url.getHost() );
152                     if ( url.getPort() != -1 )
153                     {
154                         urlBuffer.append( ":" ).append( url.getPort() );
155                     }
156                     urlBuffer.append( url.getPath() );
157 
158                     pom = urlBuffer.toString();
159                 }
160                 else
161                 {
162                     pom = pomUrl;
163                 }
164             }
165             catch ( MalformedURLException e )
166             {
167                 addActionError( getText( "add.project.unknown.error" ) );
168                 return doDefault();
169             }
170             catch ( UnsupportedEncodingException e )
171             {
172                 addActionError( getText( "add.project.unknown.error" ) );
173                 return doDefault();
174             }
175 
176         }
177         else
178         {
179             if ( pomFile != null )
180             {
181                 try
182                 {
183                     //pom = pomFile.toURL().toString();
184                     checkProtocol = false;
185                     // CONTINUUM-1897
186                     // File.c copyFile to tmp one
187                     File tmpPom = File.createTempFile( "continuum_tmp", "tmp" );
188                     FileUtils.copyFile( pomFile, tmpPom );
189                     pom = tmpPom.toURL().toString();
190                 }
191                 catch ( MalformedURLException e )
192                 {
193                     // if local file can't be converted to url it's an internal error
194                     throw new RuntimeException( e );
195                 }
196                 catch ( IOException e )
197                 {
198                     throw new RuntimeException( e );
199                 }
200             }
201             else
202             {
203                 // no url or file was filled
204                 addActionError( getText( "add.project.field.required.error" ) );
205                 return doDefault();
206             }
207         }
208 
209         ContinuumProjectBuildingResult result = doExecute( pom, selectedProjectGroup, checkProtocol, scmUseCache );
210 
211         if ( result.hasErrors() )
212         {
213             for ( String key : result.getErrors() )
214             {
215                 String cause = result.getErrorsWithCause().get( key );
216                 String msg = getText( key, new String[]{cause} );
217 
218                 // olamy : weird getText(key, String[]) must do that something like bla bla {0}
219                 // here an ugly hack for CONTINUUM-1675
220                 if ( key.equals( ContinuumProjectBuildingResult.ERROR_MISSING_SCM ) )
221                 {
222                     msg = getResourceBundle().getString( key ) + " " + cause;
223                 }
224                 if ( !StringUtils.equals( msg, key ) )
225                 {
226                     errorMessages.add( msg );
227                 }
228                 else
229                 {
230                     addActionError( msg );
231                 }
232 
233             }
234 
235             return doDefault();
236         }
237 
238         if ( this.getSelectedProjectGroup() > 0 )
239         {
240             this.setProjectGroupId( this.getSelectedProjectGroup() );
241             return "projectGroupSummary";
242         }
243 
244         if ( result.getProjectGroups() != null && !result.getProjectGroups().isEmpty() )
245         {
246             this.setProjectGroupId( ( result.getProjectGroups().get( 0 ) ).getId() );
247             return "projectGroupSummary";
248         }
249 
250         return SUCCESS;
251     }
252 
253     /**
254      * Subclasses must implement this method calling the appropiate operation on the continuum service.
255      *
256      * @param pomUrl               url of the pom specified by the user
257      * @param selectedProjectGroup project group id selected by the user
258      * @param checkProtocol        check if the protocol is allowed, use false if the pom is uploaded
259      * @return result of adding the pom to continuum
260      */
261     protected abstract ContinuumProjectBuildingResult doExecute( String pomUrl, int selectedProjectGroup,
262                                                                  boolean checkProtocol, boolean scmUseCache )
263         throws ContinuumException;
264 
265     // TODO: Remove this method because a default method return SUCCESS instead of INPUT
266     public String doDefault()
267         throws BuildDefinitionServiceException
268     {
269         return input();
270     }
271 
272     public String input()
273         throws BuildDefinitionServiceException
274     {
275         try
276         {
277             initializeProjectGroupName();
278 
279             if ( StringUtils.isEmpty( getProjectGroupName() ) )
280             {
281                 checkAddProjectGroupAuthorization();
282             }
283             else
284             {
285                 checkAddProjectToGroupAuthorization( getProjectGroupName() );
286             }
287         }
288         catch ( AuthorizationRequiredException authzE )
289         {
290             addActionError( authzE.getMessage() );
291             return REQUIRES_AUTHORIZATION;
292         }
293         Collection<ProjectGroup> allProjectGroups = getContinuum().getAllProjectGroups();
294         projectGroups = new ArrayList<ProjectGroup>();
295 
296         ProjectGroup defaultGroup = new ProjectGroup();
297         defaultGroup.setId( DEFINED_BY_POM_GROUP_ID );
298         defaultGroup.setName( "Defined by POM" );
299         projectGroups.add( defaultGroup );
300 
301         for ( ProjectGroup pg : allProjectGroups )
302         {
303             if ( isAuthorizedToAddProjectToGroup( pg.getName() ) )
304             {
305                 projectGroups.add( pg );
306             }
307         }
308 
309         initializeProjectGroupName();
310         this.setBuildDefinitionTemplates( getContinuum().getBuildDefinitionService().getAllBuildDefinitionTemplate() );
311         return INPUT;
312     }
313 
314     protected String hidePasswordInUrl( String url )
315     {
316         int indexAt = url.indexOf( "@" );
317 
318         if ( indexAt < 0 )
319         {
320             return url;
321         }
322 
323         String s = url.substring( 0, indexAt );
324 
325         int pos = s.lastIndexOf( ":" );
326 
327         return s.substring( 0, pos + 1 ) + "*****" + url.substring( indexAt );
328     }
329 
330     private void initializeProjectGroupName()
331     {
332         if ( disableGroupSelection && selectedProjectGroup != DEFINED_BY_POM_GROUP_ID )
333         {
334             try
335             {
336                 projectGroupName = getContinuum().getProjectGroup( selectedProjectGroup ).getName();
337             }
338             catch ( ContinuumException e )
339             {
340                 e.printStackTrace();
341             }
342         }
343     }
344 
345     public String getPom()
346     {
347         return pom;
348     }
349 
350     public void setPom( String pom )
351     {
352         this.pom = pom;
353     }
354 
355     public File getPomFile()
356     {
357         return pomFile;
358     }
359 
360     public void setPomFile( File pomFile )
361     {
362         this.pomFile = pomFile;
363     }
364 
365     public String getPomUrl()
366     {
367         return pomUrl;
368     }
369 
370     public void setPomUrl( String pomUrl )
371     {
372         this.pomUrl = pomUrl;
373     }
374 
375     public void setScmPassword( String scmPassword )
376     {
377         this.scmPassword = scmPassword;
378     }
379 
380     public String getScmUsername()
381     {
382         return scmUsername;
383     }
384 
385     public void setScmUsername( String scmUsername )
386     {
387         this.scmUsername = scmUsername;
388     }
389 
390     public Collection getProjectGroups()
391     {
392         return projectGroups;
393     }
394 
395     public String getProjectGroupName()
396     {
397         return projectGroupName;
398     }
399 
400     public void setProjectGroupName( String projectGroupName )
401     {
402         this.projectGroupName = projectGroupName;
403     }
404 
405     public int getSelectedProjectGroup()
406     {
407         return selectedProjectGroup;
408     }
409 
410     public void setSelectedProjectGroup( int selectedProjectGroup )
411     {
412         this.selectedProjectGroup = selectedProjectGroup;
413     }
414 
415     public boolean isDisableGroupSelection()
416     {
417         return this.disableGroupSelection;
418     }
419 
420     public void setDisableGroupSelection( boolean disableGroupSelection )
421     {
422         this.disableGroupSelection = disableGroupSelection;
423     }
424 
425     public boolean isScmUseCache()
426     {
427         return scmUseCache;
428     }
429 
430     public void setScmUseCache( boolean scmUseCache )
431     {
432         this.scmUseCache = scmUseCache;
433     }
434 
435     public int getProjectGroupId()
436     {
437         return projectGroupId;
438     }
439 
440     public void setProjectGroupId( int projectGroupId )
441     {
442         this.projectGroupId = projectGroupId;
443     }
444 
445     public List<BuildDefinitionTemplate> getBuildDefinitionTemplates()
446     {
447         return buildDefinitionTemplates;
448     }
449 
450     public void setBuildDefinitionTemplates( List<BuildDefinitionTemplate> buildDefinitionTemplates )
451     {
452         this.buildDefinitionTemplates = buildDefinitionTemplates;
453     }
454 
455     public int getBuildDefinitionTemplateId()
456     {
457         return buildDefinitionTemplateId;
458     }
459 
460     public void setBuildDefinitionTemplateId( int buildDefinitionTemplateId )
461     {
462         this.buildDefinitionTemplateId = buildDefinitionTemplateId;
463     }
464 
465     private boolean isAuthorizedToAddProjectToGroup( String projectGroupName )
466     {
467         try
468         {
469             checkAddProjectToGroupAuthorization( projectGroupName );
470             return true;
471         }
472         catch ( AuthorizationRequiredException authzE )
473         {
474             return false;
475         }
476     }
477 
478     public List<String> getErrorMessages()
479     {
480         return errorMessages;
481     }
482 
483     public void setErrorMessages( List<String> errorMessages )
484     {
485         this.errorMessages = errorMessages;
486     }
487 
488     public void setServletRequest( HttpServletRequest httpServletRequest )
489     {
490         this.httpServletRequest = httpServletRequest;
491     }
492 }