View Javadoc
1   package org.apache.maven.report.projectinfo;
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.io.InputStream;
24  import java.net.Authenticator;
25  import java.net.PasswordAuthentication;
26  import java.net.URL;
27  import java.net.URLConnection;
28  import java.security.KeyManagementException;
29  import java.security.NoSuchAlgorithmException;
30  import java.security.SecureRandom;
31  import java.security.cert.X509Certificate;
32  import java.util.Collections;
33  import java.util.List;
34  import java.util.Properties;
35  
36  import javax.net.ssl.HostnameVerifier;
37  import javax.net.ssl.HttpsURLConnection;
38  import javax.net.ssl.SSLContext;
39  import javax.net.ssl.SSLSession;
40  import javax.net.ssl.SSLSocketFactory;
41  import javax.net.ssl.TrustManager;
42  import javax.net.ssl.X509TrustManager;
43  
44  import org.apache.commons.lang.math.NumberUtils;
45  import org.apache.commons.validator.routines.RegexValidator;
46  import org.apache.commons.validator.routines.UrlValidator;
47  import org.apache.maven.artifact.Artifact;
48  import org.apache.maven.artifact.ArtifactUtils;
49  import org.apache.maven.artifact.factory.ArtifactFactory;
50  import org.apache.maven.artifact.repository.ArtifactRepository;
51  import org.apache.maven.project.MavenProject;
52  import org.apache.maven.project.MavenProjectBuilder;
53  import org.apache.maven.project.ProjectBuildingException;
54  import org.apache.maven.settings.Proxy;
55  import org.apache.maven.settings.Server;
56  import org.apache.maven.settings.Settings;
57  import org.codehaus.plexus.util.Base64;
58  import org.codehaus.plexus.util.IOUtil;
59  import org.codehaus.plexus.util.StringUtils;
60  
61  /**
62   * Utilities methods.
63   *
64   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
65   * @version $Id: ProjectInfoReportUtils.html 935177 2015-01-05 21:05:55Z michaelo $
66   * @since 2.1
67   */
68  public class ProjectInfoReportUtils
69  {
70      private static final UrlValidator URL_VALIDATOR = new UrlValidator( new String[] { "http", "https" },
71                                                                          new RegexValidator( "^([" + "\\p{Alnum}\\-\\."
72                                                                              + "]*)(:\\d*)?(.*)?" ), 0 );
73  
74      /** The timeout when getting the url input stream */
75      private static final int TIMEOUT = 1000 * 5;
76  
77      /** The default encoding used to transform bytes to characters */
78      private static final String DEFAULT_ENCODING = "UTF-8";
79  
80      /**
81       * Get the input stream using UTF-8 as character encoding from a URL.
82       *
83       * @param url not null
84       * @param settings not null to handle proxy settings
85       * @return the UTF-8 decoded input stream as string
86       * @throws IOException if any
87       * @see #getContent(URL, Settings, String)
88       */
89      public static String getContent( URL url, Settings settings )
90          throws IOException
91      {
92          return getContent( url, settings, DEFAULT_ENCODING );
93      }
94  
95      /**
96       * Get the input stream from a URL.
97       *
98       * @param url not null
99       * @param settings not null to handle proxy settings
100      * @param encoding the wanted encoding for the URL input stream. If null, UTF-8 will be used.
101      * @return the input stream decoded with the wanted encoding as string
102      * @throws IOException if any
103      */
104     public static String getContent( URL url, Settings settings, String encoding )
105         throws IOException
106     {
107         return getContent( url, null, settings, encoding );
108     }
109 
110     /**
111      * Get the input stream from a URL.
112      *
113      * @param url not null
114      * @param project could be null
115      * @param settings not null to handle proxy settings
116      * @param encoding the wanted encoding for the URL input stream. If null, UTF-8 will be used.
117      * @return the input stream decoded with the wanted encoding as string
118      * @throws IOException if any
119      * @since 2.3
120      */
121     public static String getContent( URL url, MavenProject project, Settings settings, String encoding )
122         throws IOException
123     {
124         String scheme = url.getProtocol();
125 
126         if ( StringUtils.isEmpty( encoding ) )
127         {
128             encoding = DEFAULT_ENCODING;
129         }
130 
131         if ( "file".equals( scheme ) )
132         {
133             InputStream in = null;
134             try
135             {
136                 URLConnection conn = url.openConnection();
137                 in = conn.getInputStream();
138 
139                 return IOUtil.toString( in, encoding );
140             }
141             finally
142             {
143                 IOUtil.close( in );
144             }
145         }
146 
147         Proxy proxy = settings.getActiveProxy();
148         if ( proxy != null )
149         {
150             if ( "http".equals( scheme ) || "https".equals( scheme ) || "ftp".equals( scheme ) )
151             {
152                 scheme += ".";
153             }
154             else
155             {
156                 scheme = "";
157             }
158 
159             String host = proxy.getHost();
160             if ( !StringUtils.isEmpty( host ) )
161             {
162                 Properties p = System.getProperties();
163                 p.setProperty( scheme + "proxySet", "true" );
164                 p.setProperty( scheme + "proxyHost", host );
165                 p.setProperty( scheme + "proxyPort", String.valueOf( proxy.getPort() ) );
166                 if ( !StringUtils.isEmpty( proxy.getNonProxyHosts() ) )
167                 {
168                     p.setProperty( scheme + "nonProxyHosts", proxy.getNonProxyHosts() );
169                 }
170 
171                 final String userName = proxy.getUsername();
172                 if ( !StringUtils.isEmpty( userName ) )
173                 {
174                     final String pwd = StringUtils.isEmpty( proxy.getPassword() ) ? "" : proxy.getPassword();
175                     Authenticator.setDefault( new Authenticator()
176                     {
177                         /** {@inheritDoc} */
178                         protected PasswordAuthentication getPasswordAuthentication()
179                         {
180                             return new PasswordAuthentication( userName, pwd.toCharArray() );
181                         }
182                     } );
183                 }
184             }
185         }
186 
187         InputStream in = null;
188         try
189         {
190             URLConnection conn = getURLConnection( url, project, settings );
191             in = conn.getInputStream();
192 
193             return IOUtil.toString( in, encoding );
194         }
195         finally
196         {
197             IOUtil.close( in );
198         }
199     }
200 
201     /**
202      * @param factory not null
203      * @param artifact not null
204      * @param mavenProjectBuilder not null
205      * @param remoteRepositories not null
206      * @param localRepository not null
207      * @return the artifact url or null if an error occurred.
208      */
209     // CHECKSTYLE_OFF: LineLength
210     public static String getArtifactUrl( ArtifactFactory factory, Artifact artifact,
211                                          MavenProjectBuilder mavenProjectBuilder,
212                                          List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
213     // CHECKSTYLE_ON: LineLength
214     {
215         if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
216         {
217             return null;
218         }
219 
220         Artifact copyArtifact = ArtifactUtils.copyArtifact( artifact );
221         if ( !"pom".equals( copyArtifact.getType() ) )
222         {
223             copyArtifact =
224                 factory.createProjectArtifact( copyArtifact.getGroupId(), copyArtifact.getArtifactId(),
225                                                copyArtifact.getVersion(), copyArtifact.getScope() );
226         }
227         try
228         {
229             MavenProject pluginProject =
230                 mavenProjectBuilder.buildFromRepository( copyArtifact,
231                                                          remoteRepositories == null ? Collections.EMPTY_LIST
232                                                                          : remoteRepositories, localRepository );
233 
234             if ( isArtifactUrlValid( pluginProject.getUrl() ) )
235             {
236                 return pluginProject.getUrl();
237             }
238 
239             return null;
240         }
241         catch ( ProjectBuildingException e )
242         {
243             return null;
244         }
245     }
246 
247     /**
248      * @param artifactId not null
249      * @param link could be null
250      * @return the artifactId cell with or without a link pattern
251      * @see AbstractMavenReportRenderer#linkPatternedText(String)
252      */
253     public static String getArtifactIdCell( String artifactId, String link )
254     {
255         if ( StringUtils.isEmpty( link ) )
256         {
257             return artifactId;
258         }
259 
260         return "{" + artifactId + "," + link + "}";
261     }
262 
263     /**
264      * @param url not null
265      * @return <code>true</code> if the url is valid, <code>false</code> otherwise.
266      */
267     public static boolean isArtifactUrlValid( String url )
268     {
269         if ( StringUtils.isEmpty( url ) )
270         {
271             return false;
272         }
273 
274         return URL_VALIDATOR.isValid( url );
275     }
276 
277     /**
278      * @param url not null
279      * @param project not null
280      * @param settings not null
281      * @return the url connection with auth if required. Don't check the certificate if SSL scheme.
282      * @throws IOException if any
283      */
284     private static URLConnection getURLConnection( URL url, MavenProject project, Settings settings )
285         throws IOException
286     {
287         URLConnection conn = url.openConnection();
288         conn.setConnectTimeout( TIMEOUT );
289         conn.setReadTimeout( TIMEOUT );
290 
291         // conn authorization
292         //@formatter:off
293         if ( settings.getServers() != null
294             && !settings.getServers().isEmpty()
295             && project != null
296             && project.getDistributionManagement() != null
297             && (
298                     project.getDistributionManagement().getRepository() != null
299                  || project.getDistributionManagement().getSnapshotRepository() != null
300                )
301             && ( StringUtils.isNotEmpty( project.getDistributionManagement().getRepository().getUrl() )
302                  || StringUtils.isNotEmpty( project.getDistributionManagement().getSnapshotRepository().getUrl() ) )
303                )
304         //@formatter:on
305         {
306             Server server = null;
307             if ( url.toString().contains( project.getDistributionManagement().getRepository().getUrl() ) )
308             {
309                 server = settings.getServer( project.getDistributionManagement().getRepository().getId() );
310             }
311             if ( server == null
312                 && url.toString().contains( project.getDistributionManagement().getSnapshotRepository().getUrl() ) )
313             {
314                 server = settings.getServer( project.getDistributionManagement().getSnapshotRepository().getId() );
315             }
316 
317             if ( server != null && StringUtils.isNotEmpty( server.getUsername() )
318                 && StringUtils.isNotEmpty( server.getPassword() ) )
319             {
320                 String up = server.getUsername().trim() + ":" + server.getPassword().trim();
321                 String upEncoded = new String( Base64.encodeBase64Chunked( up.getBytes() ) ).trim();
322 
323                 conn.setRequestProperty( "Authorization", "Basic " + upEncoded );
324             }
325         }
326 
327         if ( conn instanceof HttpsURLConnection )
328         {
329             HostnameVerifier hostnameverifier = new HostnameVerifier()
330             {
331                 /** {@inheritDoc} */
332                 public boolean verify( String urlHostName, SSLSession session )
333                 {
334                     return true;
335                 }
336             };
337             ( (HttpsURLConnection) conn ).setHostnameVerifier( hostnameverifier );
338 
339             TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
340             {
341                 /** {@inheritDoc} */
342                 public void checkClientTrusted( final X509Certificate[] chain, final String authType )
343                 {
344                 }
345 
346                 /** {@inheritDoc} */
347                 public void checkServerTrusted( final X509Certificate[] chain, final String authType )
348                 {
349                 }
350 
351                 /** {@inheritDoc} */
352                 public X509Certificate[] getAcceptedIssuers()
353                 {
354                     return null;
355                 }
356             } };
357 
358             try
359             {
360                 SSLContext sslContext = SSLContext.getInstance( "SSL" );
361                 sslContext.init( null, trustAllCerts, new SecureRandom() );
362 
363                 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
364 
365                 ( (HttpsURLConnection) conn ).setSSLSocketFactory( sslSocketFactory );
366             }
367             catch ( NoSuchAlgorithmException e1 )
368             {
369                 // ignore
370             }
371             catch ( KeyManagementException e )
372             {
373                 // ignore
374             }
375         }
376 
377         return conn;
378     }
379 
380     /**
381      * @param str The string to be checked.
382      * @return true if is number false otherwise.
383      */
384     public static boolean isNumber( String str )
385     {
386         if ( str.startsWith( "+" ) )
387         {
388             str = str.substring( 1 );
389         }
390         return NumberUtils.isNumber( str );
391     }
392 
393     /**
394      * @param str The string which should be converted.
395      * @param defaultValue The default value.
396      * @return Converted string.
397      */
398     public static float toFloat( String str, float defaultValue )
399     {
400         if ( str.startsWith( "+" ) )
401         {
402             str = str.substring( 1 );
403         }
404         return NumberUtils.toFloat( str, defaultValue );
405     }
406 }