View Javadoc

1   package org.apache.maven.plugin.eclipse;
2   
3   /* ====================================================================
4    *   Licensed to the Apache Software Foundation (ASF) under one or more
5    *   contributor license agreements.  See the NOTICE file distributed with
6    *   this work for additional information regarding copyright ownership.
7    *   The ASF licenses this file to You under the Apache License, Version 2.0
8    *   (the "License"); you may not use this file except in compliance with
9    *   the License.  You may obtain a copy of the License at
10   *
11   *       http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *   Unless required by applicable law or agreed to in writing, software
14   *   distributed under the License is distributed on an "AS IS" BASIS,
15   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *   See the License for the specific language governing permissions and
17   *   limitations under the License.
18   * ====================================================================
19   */
20  
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.maven.AbstractMavenComponent;
26  import org.apache.maven.project.Dependency;
27  import org.apache.maven.project.Project;
28  import org.apache.maven.util.HttpUtils;
29  
30  import java.io.File;
31  import java.io.FileNotFoundException;
32  import java.util.Iterator;
33  
34  /**
35   * A base class to download sources achives.
36   *
37   * @author <a href="snicoll@apache.org">Stephane Nicoll</a>
38   */
39  public abstract class AbstractSourcesDownloader
40      extends AbstractMavenComponent
41  {
42  
43      protected static final String PROXY_LOGINHOST = "maven.proxy.ntlm.host";
44  
45      protected static final String PROXY_LOGINDOMAIN = "maven.proxy.ntlm.domain";
46  
47      private static final Log log = LogFactory.getLog( AbstractSourcesDownloader.class );
48  
49      private Project project;
50  
51      private String groupId;
52  
53      private String artifactId;
54  
55      private String version;
56  
57      public void downloadSources()
58          throws Exception
59      {
60          if ( project == null )
61          {
62              throw new NullPointerException( "project should be set." );
63          }
64  
65          if ( groupId == null )
66          {
67              throw new NullPointerException( "groupId should be set." );
68          }
69  
70          if ( artifactId == null )
71          {
72              throw new NullPointerException( "artifactId should be set." );
73          }
74  
75          if ( version == null )
76          {
77              throw new NullPointerException( "version should be set." );
78          }
79  
80          final String dependencyId = groupId + ":" + artifactId;
81          Dependency dependency = project.getDependency( dependencyId );
82          if ( dependency == null )
83          {
84              log.warn( "Could not retrieve dependency object for[" + dependencyId + "] - skipping" );
85              return;
86          }
87  
88          String relativePath = buildRelativePath();
89          File localFile = new File( project.getContext().getMavenRepoLocal(), relativePath );
90          if ( isSnapshot() )
91          {
92              getRemoteArtifact( localFile, relativePath, dependency );
93          }
94          else
95          {
96              if ( localFile.exists() )
97              {
98                  log.debug( getSourceName() + " for[" + groupId + ":" + artifactId + ":" + version +
99                      "] is available in the local repository." );
100             }
101             else
102             {
103                 // download it
104                 getRemoteArtifact( localFile, relativePath, dependency );
105             }
106         }
107     }
108 
109     protected abstract String buildRelativePath();
110 
111     protected abstract String getSourceName();
112 
113     // Getters & Setters
114 
115 
116     public Project getProject()
117     {
118         return project;
119     }
120 
121     public void setProject( final Project project )
122     {
123         this.project = project;
124     }
125 
126     public String getGroupId()
127     {
128         return groupId;
129     }
130 
131     public void setGroupId( final String groupId )
132     {
133         this.groupId = groupId;
134     }
135 
136     public String getArtifactId()
137     {
138         return artifactId;
139     }
140 
141     public void setArtifactId( final String artifactId )
142     {
143         this.artifactId = artifactId;
144     }
145 
146     public String getVersion()
147     {
148         return version;
149     }
150 
151     public void setVersion( final String version )
152     {
153         this.version = version;
154     }
155 
156     protected boolean isSnapshot()
157     {
158         return version.endsWith( "SNAPSHOT" );
159     }
160 
161     /**
162      * Retrieve a <code>remoteFile</code> from the maven remote repositories
163      * and store it at <code>destinationFile</code>
164      *
165      * @param destinationFile the destination file in the local repository
166      * @param relativePath    the relative path to the dependency
167      * @return true if the retrieval succeeds, false otherwise.
168      */
169     protected boolean getRemoteArtifact( File destinationFile, String relativePath, Dependency relatedDependency )
170     {
171 
172         // The directory structure for the project this dependency belongs to
173         // may not exists so attempt to create the project directory structure
174         // before attempting to download the dependency.
175         File directory = destinationFile.getParentFile();
176 
177         if ( !directory.exists() )
178         {
179             directory.mkdirs();
180         }
181 
182         log.info( "Attempting to download " + getSourceName() + " for " + relatedDependency.getArtifact() );
183 
184         boolean artifactFound = false;
185 
186         for ( Iterator i = getProject().getContext().getMavenRepoRemote().iterator(); i.hasNext(); )
187         {
188             String remoteRepo = (String) i.next();
189 
190             if ( remoteRepo.endsWith( "/" ) )
191             {
192                 remoteRepo = remoteRepo.substring( 0, remoteRepo.length() - 1 );
193             }
194 
195             // The username and password parameters are not being
196             // used here. Those are the "" parameters you see below.
197             String url = remoteRepo + "/" + relativePath;
198             url = StringUtils.replace( url, "//", "/" );
199 
200             if ( !url.startsWith( "file" ) )
201             {
202                 if ( url.startsWith( "https" ) )
203                 {
204                     url = StringUtils.replace( url, "https:/", "https://" );
205                 }
206                 else
207                 {
208                     url = StringUtils.replace( url, "http:/", "http://" );
209                 }
210             }
211             log.debug( "Trying to download " + getSourceName() + " at " + url );
212 
213             // Attempt to retrieve the artifact and set the checksum if retrieval
214             // of the checksum file was successful.
215             try
216             {
217                 String loginHost = (String) getProject().getContext().getVariable( PROXY_LOGINHOST );
218                 String loginDomain = (String) getProject().getContext().getVariable( PROXY_LOGINDOMAIN );
219                 HttpUtils.getFile( url, destinationFile, false, true, getProject().getContext().getProxyHost(),
220                                    getProject().getContext().getProxyPort(),
221                                    getProject().getContext().getProxyUserName(),
222                                    getProject().getContext().getProxyPassword(), loginHost, loginDomain, true );
223 
224                 // Artifact was found, continue checking additional remote repos (if any)
225                 // in case there is a newer version (i.e. snapshots) in another repo
226                 artifactFound = true;
227 
228                 if ( !isSnapshot() )
229                 {
230                     break;
231                 }
232             }
233             catch ( FileNotFoundException e )
234             {
235                 // Multiple repositories may exist, and if the file is not found
236                 // in just one of them, it's no problem, and we don't want to
237                 // even print out an error.
238                 // if it's not found at all, artifactFound will be false, and the
239                 // build _will_ break, and the user will get an error message
240                 log.debug( "File not found on one of the repos", e );
241             }
242             catch ( Exception e )
243             {
244                 // If there are additional remote repos, then ignore exception
245                 // as artifact may be found in another remote repo. If there
246                 // are no more remote repos to check and the artifact wasn't found in
247                 // a previous remote repo, then artifactFound is false indicating
248                 // that the artifact could not be found in any of the remote repos
249                 //
250                 // arguably, we need to give the user better control (another command-
251                 // line switch perhaps) of what to do in this case? Maven already has
252                 // a command-line switch to work in offline mode, but what about when
253                 // one of two or more remote repos is unavailable? There may be multiple
254                 // remote repos for redundancy, in which case you probably want the build
255                 // to continue. There may however be multiple remote repos because some
256                 // artifacts are on one, and some are on another. In this case, you may
257                 // want the build to break.
258                 //
259                 // print a warning, in any case, so user catches on to mistyped
260                 // hostnames, or other snafus
261                 // FIXME: localize this message
262                 String[] parsedUrl = HttpUtils.parseUrl( url );
263                 log.warn( "Error retrieving artifact from [" + parsedUrl[2] + "]: " + e );
264                 if ( parsedUrl[0] != null )
265                 {
266                     log.debug( "Username was '" + parsedUrl[0] + "', password hidden" );
267                 }
268                 log.debug( "Error details", e );
269             }
270         }
271 
272         return artifactFound;
273     }
274 
275 }