View Javadoc

1   package org.apache.maven.continuum.project.builder;
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.io.IOUtils;
23  import org.apache.http.HttpException;
24  import org.apache.http.HttpHost;
25  import org.apache.http.HttpResponse;
26  import org.apache.http.HttpVersion;
27  import org.apache.http.auth.AuthScope;
28  import org.apache.http.auth.UsernamePasswordCredentials;
29  import org.apache.http.client.AuthCache;
30  import org.apache.http.client.methods.HttpGet;
31  import org.apache.http.client.protocol.ClientContext;
32  import org.apache.http.conn.ClientConnectionManager;
33  import org.apache.http.conn.params.ConnManagerPNames;
34  import org.apache.http.conn.params.ConnPerRouteBean;
35  import org.apache.http.conn.scheme.PlainSocketFactory;
36  import org.apache.http.conn.scheme.Scheme;
37  import org.apache.http.conn.scheme.SchemeRegistry;
38  import org.apache.http.impl.auth.BasicScheme;
39  import org.apache.http.impl.client.BasicAuthCache;
40  import org.apache.http.impl.client.DefaultHttpClient;
41  import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
42  import org.apache.http.params.BasicHttpParams;
43  import org.apache.http.params.HttpParams;
44  import org.apache.http.params.HttpProtocolParams;
45  import org.apache.http.protocol.BasicHttpContext;
46  import org.apache.http.util.EntityUtils;
47  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
48  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
49  import org.codehaus.plexus.util.FileUtils;
50  import org.codehaus.plexus.util.IOUtil;
51  import org.codehaus.plexus.util.StringUtils;
52  import org.slf4j.Logger;
53  import org.slf4j.LoggerFactory;
54  
55  import java.io.File;
56  import java.io.FileNotFoundException;
57  import java.io.FileWriter;
58  import java.io.IOException;
59  import java.io.InputStream;
60  import java.net.MalformedURLException;
61  import java.net.URI;
62  import java.net.URISyntaxException;
63  import java.net.URL;
64  import java.net.UnknownHostException;
65  
66  
67  /**
68   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
69   * @version $Id: AbstractContinuumProjectBuilder.java 1372260 2012-08-13 04:29:09Z brett $
70   */
71  public abstract class AbstractContinuumProjectBuilder
72      implements ContinuumProjectBuilder, Initializable
73  {
74      private static final String TMP_DIR = System.getProperty( "java.io.tmpdir" );
75  
76      protected final Logger log = LoggerFactory.getLogger( getClass() );
77  
78      private HttpParams params;
79  
80      private ClientConnectionManager cm;
81  
82      public void initialize()
83          throws InitializationException
84      {
85          SchemeRegistry schemeRegistry = new SchemeRegistry();
86          // http scheme
87          schemeRegistry.register( new Scheme( "http", PlainSocketFactory.getSocketFactory(), 80 ) );
88          // https scheme
89          schemeRegistry.register( new Scheme( "https", new EasySSLSocketFactory(), 443 ) );
90  
91          params = new BasicHttpParams();
92          // TODO put this values to a configuration way ???
93          params.setParameter( ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30 );
94          params.setParameter( ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean( 30 ) );
95          HttpProtocolParams.setVersion( params, HttpVersion.HTTP_1_1 );
96  
97          cm = new ThreadSafeClientConnManager( params, schemeRegistry );
98      }
99  
100     protected File createMetadataFile( URL metadata, String username, String password,
101                                        ContinuumProjectBuildingResult result )
102         throws IOException, URISyntaxException, HttpException
103     {
104         DefaultHttpClient httpClient = new DefaultHttpClient( cm, params );
105 
106         String url = metadata.toExternalForm();
107         if ( metadata.getProtocol().startsWith( "http" ) )
108         {
109             url = hidePasswordInUrl( url );
110         }
111         log.info( "Downloading " + url );
112 
113         InputStream is;
114 
115         if ( metadata.getProtocol().startsWith( "http" ) )
116         {
117             URI uri = metadata.toURI();
118             HttpGet httpGet = new HttpGet( uri );
119 
120             httpClient.getCredentialsProvider().clear();
121 
122             // basic auth
123             if ( username != null && password != null )
124             {
125                 httpClient.getCredentialsProvider().setCredentials( new AuthScope( uri.getHost(), uri.getPort() ),
126                                                                     new UsernamePasswordCredentials( username,
127                                                                                                      password ) );
128             }
129 
130             // basic auth
131             HttpResponse httpResponse = httpClient.execute( httpGet );
132 
133             // CONTINUUM-2627
134             if ( httpResponse.getStatusLine().getStatusCode() != 200 )
135             {
136                 log.debug( "Initial attempt did not return a 200 status code. Trying pre-emptive authentication.." );
137 
138                 HttpHost targetHost = new HttpHost( uri.getHost(), uri.getPort(), uri.getScheme() );
139 
140                 // Create AuthCache instance
141                 AuthCache authCache = new BasicAuthCache();
142                 // Generate BASIC scheme object and add it to the local auth cache
143                 BasicScheme basicAuth = new BasicScheme();
144                 authCache.put( targetHost, basicAuth );
145 
146                 // Add AuthCache to the execution context
147                 BasicHttpContext localcontext = new BasicHttpContext();
148                 localcontext.setAttribute( ClientContext.AUTH_CACHE, authCache );
149 
150                 httpResponse = httpClient.execute( targetHost, httpGet, localcontext );
151             }
152 
153             int res = httpResponse.getStatusLine().getStatusCode();
154 
155             switch ( res )
156             {
157                 case 200:
158                     break;
159                 case 401:
160                     log.error( "Error adding project: Unauthorized " + url );
161                     result.addError( ContinuumProjectBuildingResult.ERROR_UNAUTHORIZED );
162                     return null;
163                 default:
164                     log.warn( "skip non handled http return code " + res );
165             }
166             is = IOUtils.toInputStream( EntityUtils.toString( httpResponse.getEntity(), EntityUtils.getContentCharSet(
167                 httpResponse.getEntity() ) ) );
168         }
169         else
170         {
171             is = metadata.openStream();
172         }
173 
174         String path = metadata.getPath();
175 
176         String baseDirectory;
177 
178         String fileName;
179 
180         int lastIndex = path.lastIndexOf( "/" );
181 
182         if ( lastIndex >= 0 )
183         {
184             baseDirectory = path.substring( 0, lastIndex );
185 
186             // Required for windows
187             int colonIndex = baseDirectory.indexOf( ":" );
188 
189             if ( colonIndex >= 0 )
190             {
191                 baseDirectory = baseDirectory.substring( colonIndex + 1 );
192             }
193 
194             fileName = path.substring( lastIndex + 1 );
195         }
196         else
197         {
198             baseDirectory = "";
199 
200             fileName = path;
201         }
202 
203         // Little hack for URLs that contains '*' like "http://svn.codehaus.org/*checkout*/trunk/pom.xml?root=plexus"
204         baseDirectory = StringUtils.replace( baseDirectory, "*", "" );
205 
206         File continuumTmpDir = new File( TMP_DIR, "continuum" );
207 
208         // FIXME should deleted after has been reading
209         File uploadDirectory = new File( continuumTmpDir, baseDirectory );
210 
211         uploadDirectory.deleteOnExit();
212 
213         // resolve any '..' as it will cause issues
214         uploadDirectory = uploadDirectory.getCanonicalFile();
215 
216         uploadDirectory.mkdirs();
217 
218         FileUtils.forceDeleteOnExit( continuumTmpDir );
219 
220         File file = new File( uploadDirectory, fileName );
221 
222         file.deleteOnExit();
223 
224         FileWriter writer = new FileWriter( file );
225 
226         IOUtil.copy( is, writer );
227 
228         is.close();
229 
230         writer.close();
231 
232         return file;
233     }
234 
235     private String hidePasswordInUrl( String url )
236     {
237         int indexAt = url.indexOf( "@" );
238 
239         if ( indexAt < 0 )
240         {
241             return url;
242         }
243 
244         String s = url.substring( 0, indexAt );
245 
246         int pos = s.lastIndexOf( ":" );
247 
248         return s.substring( 0, pos + 1 ) + "*****" + url.substring( indexAt );
249     }
250 
251     /**
252      * Create metadata file and handle exceptions, adding the errors to the result object.
253      *
254      * @param result   holder with result and errors.
255      * @param metadata
256      * @param username
257      * @param password
258      * @return
259      */
260     protected File createMetadataFile( ContinuumProjectBuildingResult result, URL metadata, String username,
261                                        String password )
262     {
263         String url = metadata.toExternalForm();
264 
265         if ( metadata.getProtocol().startsWith( "http" ) )
266         {
267             url = hidePasswordInUrl( url );
268         }
269 
270         try
271         {
272             return createMetadataFile( metadata, username, password, result );
273         }
274         catch ( FileNotFoundException e )
275         {
276             log.info( "URL not found: " + url, e );
277             result.addError( ContinuumProjectBuildingResult.ERROR_POM_NOT_FOUND );
278         }
279         catch ( MalformedURLException e )
280         {
281             log.info( "Malformed URL: " + url, e );
282             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
283         }
284         catch ( URISyntaxException e )
285         {
286             log.info( "Malformed URL: " + url, e );
287             result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL );
288         }
289         catch ( UnknownHostException e )
290         {
291             log.info( "Unknown host: " + url, e );
292             result.addError( ContinuumProjectBuildingResult.ERROR_UNKNOWN_HOST );
293         }
294         catch ( IOException e )
295         {
296             log.warn( "Could not download the URL: " + url, e );
297             result.addError( ContinuumProjectBuildingResult.ERROR_UNKNOWN );
298         }
299         catch ( HttpException e )
300         {
301             log.warn( "Could not download the URL: " + url, e );
302             result.addError( ContinuumProjectBuildingResult.ERROR_UNKNOWN );
303         }
304         return null;
305     }
306 
307 }