63764f53439d2c6ce836cb437ad2db100a4792f7
[utils] / crawler / basic / src / org / wamblee / crawler / AbstractPageRequest.java
1 /*
2  * Copyright 2005 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.wamblee.crawler;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.PrintStream;
23
24 import javax.xml.transform.OutputKeys;
25 import javax.xml.transform.Transformer;
26 import javax.xml.transform.TransformerFactory;
27 import javax.xml.transform.dom.DOMSource;
28 import javax.xml.transform.stream.StreamResult;
29
30 import org.apache.commons.httpclient.Header;
31 import org.apache.commons.httpclient.HttpClient;
32 import org.apache.commons.httpclient.HttpException;
33 import org.apache.commons.httpclient.HttpMethod;
34 import org.apache.commons.httpclient.HttpStatus;
35 import org.apache.commons.httpclient.NameValuePair;
36 import org.apache.commons.httpclient.methods.GetMethod;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.w3c.dom.Document;
40 import org.w3c.tidy.Tidy;
41 import org.wamblee.xml.XSLT;
42
43 /**
44  * General support claas for all kinds of requests.
45  */
46 public abstract class AbstractPageRequest implements PageRequest {
47
48     private static final Log LOG = LogFactory.getLog(AbstractPageRequest.class);
49     private static final String REDIRECT_HEADER = "Location";
50
51     private NameValuePair[] _params;
52
53     private String _xslt;
54     
55     private PrintStream _os; 
56
57     protected AbstractPageRequest(NameValuePair[] aParams, String aXslt, PrintStream aOs) {
58         if ( aParams == null ) { 
59             throw new IllegalArgumentException("aParams is null");
60         }
61         if ( aXslt == null ) { 
62             throw new IllegalArgumentException("aXslt is null");
63         }
64         _params = aParams;
65         _xslt = aXslt;
66         _os = aOs; 
67     }
68     
69     /* (non-Javadoc)
70      * @see org.wamblee.crawler.PageRequest#overrideXslt(java.lang.String)
71      */
72     public void overrideXslt(String aXslt) {
73         _xslt = aXslt;   
74     }
75     
76     protected NameValuePair[] getParameters() { 
77         return _params;
78     }
79
80     protected Document executeMethod(HttpClient client, HttpMethod method) {
81         try {
82             // Execute the method.
83             method = executeWithRedirects(client, method);
84
85             // Transform the HTML into wellformed XML.
86             Tidy tidy = new Tidy();
87             tidy.setXHTML(true);
88             tidy.setQuiet(true); 
89             tidy.setShowWarnings(false);
90             if ( _os != null ) { 
91                 _os.println("Content of '" + method.getURI() + "'");
92                 _os.println();
93             }
94             // We let jtidy produce raw output because the DOM it produces is 
95             // is not namespace aware. We let the XSLT processor parse the XML again
96             // to ensure that the XSLT uses a namespace aware DOM tree. An alternative 
97             // is to configure namespace awareness of the XML parser in a system wide way. 
98             ByteArrayOutputStream xhtml = new ByteArrayOutputStream();
99             tidy.parse(method.getResponseBodyAsStream(), xhtml);
100             _os.print(new String(xhtml.toByteArray()));
101             // Obtaining the XML as dom is not used. 
102             //Document w3cDoc = tidy.parseDOM(method.getResponseBodyAsStream(),
103             //        _os);
104             if ( _os != null ) { 
105                 _os.println();
106             }
107             xhtml.flush();
108             byte[] xhtmlData = xhtml.toByteArray();
109             Document transformed = XSLT.transform(xhtmlData, new File(_xslt));
110             _os.println("Transformed result is: ");
111             Transformer transformer = TransformerFactory.newInstance().newTransformer();
112             transformer.setParameter(OutputKeys.INDENT, "yes");
113             transformer.setParameter(OutputKeys.METHOD, "xml");
114             transformer.transform(new DOMSource(transformed), new StreamResult(_os));
115             
116             return transformed;
117         } catch (Exception e) {
118             throw new RuntimeException(e.getMessage(), e);
119         } finally {
120             // Release the connection.
121             method.releaseConnection();
122         }
123     }
124
125     /**
126      * @param aClient
127      * @param aMethod
128      * @throws IOException
129      * @throws HttpException
130      */
131     private HttpMethod executeWithRedirects(HttpClient aClient, HttpMethod aMethod) throws IOException, HttpException {
132         int statusCode = aClient.executeMethod(aMethod);
133
134         switch (statusCode) { 
135         case HttpStatus.SC_OK: {
136             return aMethod;
137         }
138         case HttpStatus.SC_MOVED_PERMANENTLY:
139         case HttpStatus.SC_MOVED_TEMPORARILY:
140         case HttpStatus.SC_SEE_OTHER: {
141             aMethod.releaseConnection();
142             Header header = aMethod.getResponseHeader(REDIRECT_HEADER);
143             aMethod = new GetMethod(header.getValue());
144             return executeWithRedirects(aClient, aMethod); // TODO protect against infinite recursion.
145         }
146         default: {
147             throw new RuntimeException("Method failed: "
148                     + aMethod.getStatusLine());
149         }
150         }
151     }
152 }