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