View Javadoc

1   /*
2    * Maven SourceForge plugin 
3    * Author: Ludovic Claude (ludovicc@users.sourceforge.net)
4    * Distributable under BSD license.
5    */
6   
7   package net.sourceforge.mavenplugins.sourceforge;
8   
9   import java.io.BufferedInputStream;
10  import java.io.File;
11  import java.io.FileOutputStream;
12  import java.io.IOException;
13  import java.io.InputStream;
14  import java.io.StringReader;
15  import java.net.InetAddress;
16  import java.net.UnknownHostException;
17  
18  import org.apache.commons.httpclient.Header;
19  import org.apache.commons.httpclient.HttpClient;
20  import org.apache.commons.httpclient.HttpMethod;
21  import org.apache.commons.httpclient.HttpRecoverableException;
22  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
23  import org.apache.commons.httpclient.NTCredentials;
24  import org.apache.commons.httpclient.URI;
25  import org.apache.commons.httpclient.URIException;
26  import org.apache.commons.httpclient.UsernamePasswordCredentials;
27  import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
28  import org.apache.commons.httpclient.cookie.CookiePolicy;
29  import org.apache.commons.httpclient.methods.GetMethod;
30  import org.apache.commons.httpclient.protocol.Protocol;
31  import org.apache.xerces.xni.parser.XMLInputSource;
32  import org.cyberneko.html.parsers.DOMParser;
33  import org.w3c.dom.Document;
34  import org.xml.sax.SAXNotRecognizedException;
35  import org.xml.sax.SAXNotSupportedException;
36  
37  /***
38   * Emulates a web browser
39   *  
40   * @author <a href="mailto:ludovicc@users.sourceforge.net">Ludovic Claude</a>
41   * @author Stephen Colebourne
42   * @version $Revision: 1.3 $ $Date: 2006/01/07 22:50:45 $
43   * @created on 11 oct. 2003
44   */
45  public class WebBrowser {
46      
47      static {
48          // kill HttpClient logging
49          System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
50          System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
51          System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "error");
52      }
53      
54      private static WebBrowser _instance = new WebBrowser();
55      
56      private HttpClient _client;
57      private DOMParser _parser;
58      
59      /***
60       * @return the singleton instance
61       */
62      public static WebBrowser getInstance() {
63          return _instance;    
64      }
65      
66      public static String forceFinalSlash(String s) {
67          if (!s.endsWith("/")) {
68              return s + "/";
69          }
70          return s;
71      }
72      
73      public static String removeFinalSlash(String s) {
74          if (s.endsWith("/")) {
75              return s.substring(0, s.length()-1);
76          }
77          return s;
78      }
79      
80      /***
81       * Constructor for WebBrowser
82       */
83      private WebBrowser() {
84          super();
85          CookiePolicy.setDefaultPolicy(CookiePolicy.COMPATIBILITY);
86          Protocol.registerProtocol("https", 
87                  new Protocol("https", new EasySSLProtocolSocketFactory(), 443));
88          _client = new HttpClient(new MultiThreadedHttpConnectionManager());
89          _parser = new DOMParser();
90          try {
91              _parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower");
92          } catch (SAXNotRecognizedException e) {
93              e.printStackTrace();
94          } catch (SAXNotSupportedException e) {
95              e.printStackTrace();
96          }
97      }
98  
99      /***
100      * Gets the client.
101      * @return the client.
102      */
103     public HttpClient getClient() {
104         return _client;
105     }
106 
107     /***
108      * Use a proxy to bypass the firewall
109      *
110      * @param proxyHost Host of the proxy
111      * @param proxyPort Port of the proxy
112      * @param proxyNTDomain NT domain for authentification on a MS proxy
113      * @param userName Username (if authentification is required), or null
114      * @param password Password (if authentification is required), or null
115      */
116     public void useProxy(String proxyHost, int proxyPort, final String ntDomain, final String userName, String password) {
117         System.out.println("Using proxy " + proxyHost + ":" + proxyPort);
118         _client.getHostConfiguration().setProxy(proxyHost, proxyPort);
119         if (userName != null) {
120             if (ntDomain == null) {
121                 System.out.println("Login on the proxy with user name " + userName);
122                 _client.getState().setProxyCredentials(null, proxyHost,
123                     new UsernamePasswordCredentials(userName, password));
124             } else {
125                 try {
126                     String host = InetAddress.getLocalHost().getHostName();
127                     System.out.println("Login on the NT proxy with user name " + userName
128                             + ", host " + host + ", NT domain " + ntDomain);
129                     _client.getState().setProxyCredentials(null, proxyHost,
130                         new NTCredentials(userName, password, host, ntDomain));
131                 } catch (UnknownHostException ex) {
132                     ex.printStackTrace();
133                 }
134             }
135         }
136     }
137     
138     /***
139      * Execute a http method
140      * 
141      * @param method The method
142      * @return the last http method executed (after following redirects)
143      */
144     public HttpMethod executeMethod(HttpMethod method) throws URIException {
145         int statusCode = -1;
146         int attempt = 0;
147     
148         method.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98)");
149     
150         // We will retry up to 3 times.
151         while ((statusCode == -1) && (attempt < 3)) {
152             try {
153                 // execute the method.
154                 statusCode = _client.executeMethod(method);
155             } catch (HttpRecoverableException e) {
156                 System.out.println("A recoverable exception occurred, retrying.  " + e.getMessage());
157             } catch (IOException e) {
158                 System.out.println("Failed to download file.");
159                 e.printStackTrace();
160                 throw new RuntimeException("Failed to download file.");
161             }
162         }
163     
164         // Check that we didn't run out of retries.
165         if (statusCode == -1) {
166             System.out.println("Failed to recover from exception.");
167             throw new RuntimeException("Error when reading " + method.getPath());
168         }
169     
170         if (statusCode >= 400) {
171             System.out.println("Page not found (error " + statusCode + ")");
172             throw new RuntimeException("Error when reading " + method.getPath());
173         }
174     
175         // Tests for redirects
176         if ((statusCode >= 300) && (statusCode < 400)) {
177             Header locationHeader = method.getResponseHeader("location");
178             if (locationHeader == null) {
179                 locationHeader = method.getResponseHeader("Location");
180             }
181     
182             if (locationHeader != null) {
183                 String redirectLocation = locationHeader.getValue();
184                 
185                 method.releaseConnection();    
186     
187                 URI uri = new URI(redirectLocation);
188                 if (!uri.isAbsoluteURI()) {
189                     uri = method.getURI();
190                     if (!redirectLocation.startsWith("/")) {
191                         redirectLocation = uri.getCurrentHierPath() + "/" + redirectLocation;
192                     }
193                     uri.setPath(redirectLocation);
194                     redirectLocation = uri.getURI();
195                 }
196                 
197                 HttpMethod redirectMethod = new GetMethod(redirectLocation);
198                 
199                 // need to set up no follow redirects each time
200                 // this is because we handle redirects here in this method
201                 redirectMethod.setFollowRedirects(false);
202     
203                 redirectMethod = executeMethod(redirectMethod);
204     
205                 return redirectMethod;
206             } else {
207                 // The response is invalid and did not provide the new location for
208                 // the resource.  Report an error or possibly handle the response
209                 // like a 404 Not Found error.
210                 System.out.println("Page not found");
211                 throw new RuntimeException("Error when reading " + method);
212             }
213         }
214     
215         return method;
216     }
217 
218     /***
219      * Gets the response from a method that has been executed
220      * 
221      * @param method
222      * @return
223      */
224     public String getResponse(HttpMethod method) throws URIException {
225         HttpMethod lastMethod = executeMethod(method);
226         String response = new String(lastMethod.getResponseBody());
227         lastMethod.releaseConnection();
228         return response;
229     }
230     
231     /***
232      * Execute the method and gets the response as a xml document. 
233      * 
234      * @param method
235      * @return
236      */
237     public Document getDocument(HttpMethod method) throws Exception {
238         String response = getResponse(method);
239         
240         XMLInputSource source = new XMLInputSource(null, null, null, new StringReader(response), null);
241     
242         _parser.parse(source);
243     
244         Document doc = _parser.getDocument();
245         return doc;        
246     }
247 
248     public void loadFile(HttpMethod method, File destFile) throws Exception {
249         HttpMethod lastMethod = executeMethod(method);
250         InputStream in = null;
251         FileOutputStream out = null;
252         try {
253             in = new BufferedInputStream(lastMethod.getResponseBodyAsStream());
254             out = new FileOutputStream(destFile);
255 
256             byte[] buffer = new byte[8 * 1024];
257             int count = 0;
258             do {
259                 out.write(buffer, 0, count);
260                 count = in.read(buffer, 0, buffer.length);
261             } while (count != -1);
262         } finally {
263             if (out != null) {
264                 out.close();
265             }
266             if (in != null) {
267                 in.close();
268             }
269         }
270     }
271     
272 }