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