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.URI;
27  import java.net.URL;
28  import java.net.URLConnection;
29  import java.security.KeyManagementException;
30  import java.security.NoSuchAlgorithmException;
31  import java.security.SecureRandom;
32  import java.security.cert.X509Certificate;
33  import java.util.Properties;
34  
35  import javax.net.ssl.HostnameVerifier;
36  import javax.net.ssl.HttpsURLConnection;
37  import javax.net.ssl.SSLContext;
38  import javax.net.ssl.SSLSession;
39  import javax.net.ssl.SSLSocketFactory;
40  import javax.net.ssl.TrustManager;
41  import javax.net.ssl.X509TrustManager;
42  
43  import org.apache.commons.validator.routines.RegexValidator;
44  import org.apache.commons.validator.routines.UrlValidator;
45  import org.apache.maven.artifact.Artifact;
46  import org.apache.maven.artifact.ArtifactUtils;
47  import org.apache.maven.project.MavenProject;
48  import org.apache.maven.project.ProjectBuilder;
49  import org.apache.maven.project.ProjectBuildingException;
50  import org.apache.maven.project.ProjectBuildingRequest;
51  import org.apache.maven.reporting.AbstractMavenReportRenderer;
52  import org.apache.maven.repository.RepositorySystem;
53  import org.apache.maven.settings.Proxy;
54  import org.apache.maven.settings.Server;
55  import org.apache.maven.settings.Settings;
56  import org.codehaus.plexus.util.Base64;
57  import org.codehaus.plexus.util.IOUtil;
58  import org.codehaus.plexus.util.StringUtils;
59  
60  /**
61   * Utilities methods.
62   *
63   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
64   * @version $Id$
65   * @since 2.1
66   */
67  public class ProjectInfoReportUtils
68  {
69      private static final UrlValidator URL_VALIDATOR = new UrlValidator( new String[] { "http", "https" },
70                                                                          new RegexValidator( "^([" + "\\p{Alnum}\\-\\."
71                                                                              + "]*)(:\\d*)?(.*)?" ), 0 );
72  
73      /** The timeout when getting the url input stream */
74      private static final int TIMEOUT = 1000 * 5;
75  
76      /** The default encoding used to transform bytes to characters */
77      private static final String DEFAULT_ENCODING = "UTF-8";
78  
79      /**
80       * Get the input stream using UTF-8 as character encoding from a URL.
81       *
82       * @param url not null
83       * @param settings not null to handle proxy settings
84       * @return the UTF-8 decoded input stream as string
85       * @throws IOException if any
86       * @see #getContent(URL, Settings, String)
87       */
88      public static String getContent( URL url, Settings settings )
89          throws IOException
90      {
91          return getContent( url, settings, DEFAULT_ENCODING );
92      }
93  
94      /**
95       * Get the input stream from a URL.
96       *
97       * @param url not null
98       * @param settings not null to handle proxy settings
99       * @param encoding the wanted encoding for the URL input stream. If null, UTF-8 will be used.
100      * @return the input stream decoded with the wanted encoding as string
101      * @throws IOException if any
102      */
103     public static String getContent( URL url, Settings settings, String encoding )
104         throws IOException
105     {
106         return getContent( url, null, settings, encoding );
107     }
108 
109     /**
110      * Get the input stream from a URL.
111      *
112      * @param url not null
113      * @param project could be null
114      * @param settings not null to handle proxy settings
115      * @param encoding the wanted encoding for the URL input stream. If null, UTF-8 will be used.
116      * @return the input stream decoded with the wanted encoding as string
117      * @throws IOException if any
118      * @since 2.3
119      */
120     public static String getContent( URL url, MavenProject project, Settings settings, String encoding )
121         throws IOException
122     {
123         String scheme = url.getProtocol();
124 
125         if ( StringUtils.isEmpty( encoding ) )
126         {
127             encoding = DEFAULT_ENCODING;
128         }
129 
130         if ( "file".equals( scheme ) )
131         {
132             InputStream in = null;
133             try
134             {
135                 URLConnection conn = url.openConnection();
136                 in = conn.getInputStream();
137 
138                 final String content = IOUtil.toString( in, encoding );
139 
140                 in.close();
141                 in = null;
142 
143                 return content;
144             }
145             finally
146             {
147                 IOUtil.close( in );
148             }
149         }
150 
151         Proxy proxy = settings.getActiveProxy();
152         if ( proxy != null )
153         {
154             if ( "http".equals( scheme ) || "https".equals( scheme ) || "ftp".equals( scheme ) )
155             {
156                 scheme += ".";
157             }
158             else
159             {
160                 scheme = "";
161             }
162 
163             String host = proxy.getHost();
164             if ( !StringUtils.isEmpty( host ) )
165             {
166                 Properties p = System.getProperties();
167                 p.setProperty( scheme + "proxySet", "true" );
168                 p.setProperty( scheme + "proxyHost", host );
169                 p.setProperty( scheme + "proxyPort", String.valueOf( proxy.getPort() ) );
170                 if ( !StringUtils.isEmpty( proxy.getNonProxyHosts() ) )
171                 {
172                     p.setProperty( scheme + "nonProxyHosts", proxy.getNonProxyHosts() );
173                 }
174 
175                 final String userName = proxy.getUsername();
176                 if ( !StringUtils.isEmpty( userName ) )
177                 {
178                     final String pwd = StringUtils.isEmpty( proxy.getPassword() ) ? "" : proxy.getPassword();
179                     Authenticator.setDefault( new Authenticator()
180                     {
181                         /** {@inheritDoc} */
182                         @Override
183                         protected PasswordAuthentication getPasswordAuthentication()
184                         {
185                             return new PasswordAuthentication( userName, pwd.toCharArray() );
186                         }
187                     } );
188                 }
189             }
190         }
191 
192         InputStream in = null;
193         try
194         {
195             URLConnection conn = getURLConnection( url, project, settings );
196             in = conn.getInputStream();
197 
198             final String string = IOUtil.toString( in, encoding );
199 
200             in.close();
201             in = null;
202 
203             return string;
204         }
205         finally
206         {
207             IOUtil.close( in );
208         }
209     }
210 
211     /**
212      * @param repositorySystem not null
213      * @param artifact not null
214      * @param projectBuilder not null
215      * @param buildingRequest not null
216      * @return the artifact url or null if an error occurred.
217      */
218     public static String getArtifactUrl( RepositorySystem repositorySystem, Artifact artifact,
219                                          ProjectBuilder projectBuilder, ProjectBuildingRequest buildingRequest )
220     {
221         if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
222         {
223             return null;
224         }
225 
226         Artifact copyArtifact = ArtifactUtils.copyArtifact( artifact );
227         if ( !"pom".equals( copyArtifact.getType() ) )
228         {
229             copyArtifact =
230                 repositorySystem.createProjectArtifact( copyArtifact.getGroupId(), copyArtifact.getArtifactId(),
231                                                         copyArtifact.getVersion() );
232         }
233         try
234         {
235             MavenProject pluginProject = projectBuilder.build( copyArtifact, buildingRequest ).getProject();
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      * Convenience method to return the name of a web-based mailing list archive server.
282      * For instance, if the archive URI is <code>http://www.mail-archive.com/dev@maven.apache.org</code>, this
283      * method returns <code>www.mail-archive.com</code>
284      *
285      * @param uri the URI parse
286      * @return the server host of a web-based mailing list archive server
287      */
288     public static String getArchiveServer( String uri )
289     {
290         if ( uri == null )
291         {
292             return "???UNKNOWN???";
293         }
294         return URI.create( uri ).getHost();
295     }
296 
297     /**
298      * @param url not null
299      * @param project not null
300      * @param settings not null
301      * @return the url connection with auth if required. Don't check the certificate if SSL scheme.
302      * @throws IOException if any
303      */
304     private static URLConnection getURLConnection( URL url, MavenProject project, Settings settings )
305         throws IOException
306     {
307         URLConnection conn = url.openConnection();
308         conn.setConnectTimeout( TIMEOUT );
309         conn.setReadTimeout( TIMEOUT );
310 
311         // conn authorization
312         //@formatter:off
313         if ( settings.getServers() != null
314             && !settings.getServers().isEmpty()
315             && project != null
316             && project.getDistributionManagement() != null
317             && (
318                     project.getDistributionManagement().getRepository() != null
319                  || project.getDistributionManagement().getSnapshotRepository() != null
320                )
321             && ( StringUtils.isNotEmpty( project.getDistributionManagement().getRepository().getUrl() )
322                  || StringUtils.isNotEmpty( project.getDistributionManagement().getSnapshotRepository().getUrl() ) )
323                )
324         //@formatter:on
325         {
326             Server server = null;
327             if ( url.toString().contains( project.getDistributionManagement().getRepository().getUrl() ) )
328             {
329                 server = settings.getServer( project.getDistributionManagement().getRepository().getId() );
330             }
331             if ( server == null
332                 && url.toString().contains( project.getDistributionManagement().getSnapshotRepository().getUrl() ) )
333             {
334                 server = settings.getServer( project.getDistributionManagement().getSnapshotRepository().getId() );
335             }
336 
337             if ( server != null && StringUtils.isNotEmpty( server.getUsername() )
338                 && StringUtils.isNotEmpty( server.getPassword() ) )
339             {
340                 String up = server.getUsername().trim() + ":" + server.getPassword().trim();
341                 String upEncoded = new String( Base64.encodeBase64Chunked( up.getBytes() ) ).trim();
342 
343                 conn.setRequestProperty( "Authorization", "Basic " + upEncoded );
344             }
345         }
346 
347         if ( conn instanceof HttpsURLConnection )
348         {
349             HostnameVerifier hostnameverifier = new HostnameVerifier()
350             {
351                 /** {@inheritDoc} */
352                 public boolean verify( String urlHostName, SSLSession session )
353                 {
354                     return true;
355                 }
356             };
357             ( (HttpsURLConnection) conn ).setHostnameVerifier( hostnameverifier );
358 
359             TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
360             {
361                 /** {@inheritDoc} */
362                 public void checkClientTrusted( final X509Certificate[] chain, final String authType )
363                 {
364                 }
365 
366                 /** {@inheritDoc} */
367                 public void checkServerTrusted( final X509Certificate[] chain, final String authType )
368                 {
369                 }
370 
371                 /** {@inheritDoc} */
372                 public X509Certificate[] getAcceptedIssuers()
373                 {
374                     return null;
375                 }
376             } };
377 
378             try
379             {
380                 SSLContext sslContext = SSLContext.getInstance( "SSL" );
381                 sslContext.init( null, trustAllCerts, new SecureRandom() );
382 
383                 SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
384 
385                 ( (HttpsURLConnection) conn ).setSSLSocketFactory( sslSocketFactory );
386             }
387             catch ( NoSuchAlgorithmException | KeyManagementException e1 )
388             {
389                 // ignore
390             }
391         }
392 
393         return conn;
394     }
395 }