001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.util;
039:
040: import java.io.File;
041: import java.io.FileWriter;
042: import java.io.IOException;
043: import java.util.Iterator;
044: import java.util.List;
045:
046: import org.apache.commons.httpclient.NameValuePair;
047: import org.apache.commons.io.FileUtils;
048: import org.apache.commons.logging.Log;
049: import org.apache.commons.logging.LogFactory;
050:
051: import com.gargoylesoftware.htmlunit.TextUtil;
052: import com.gargoylesoftware.htmlunit.WebConnection;
053: import com.gargoylesoftware.htmlunit.WebRequestSettings;
054: import com.gargoylesoftware.htmlunit.WebResponse;
055:
056: /**
057: * Wrapper around a "real" WebConnection that will use the wrapped web connection
058: * to do the real job and save all received responses
059: * in the temp directory with an overview page.<br>
060: * <br>
061: * This may be useful at conception time to understand what is "browsed".<br>
062: * <br>
063: * Example:
064: * <pre>
065: * final WebClient client = new WebClient();
066: * final WebConnection connection = new DebuggingWebConnection(client.getWebConnection(), "myTest");
067: * client.setWebConnection(connection);
068: * </pre>
069: * In this example an overview page will be generated under the name myTest.html in the temp directory.<br>
070: * <br>
071: * <em>This class is only intended as an help during the conception.</em>
072: *
073: * @version $Revision: 2132 $
074: * @author Marc Guillemot
075: * @author Ahmed Ashour
076: */
077: public class DebuggingWebConnection extends WebConnectionWrapper {
078: private static final Log LOG = LogFactory
079: .getLog(DebuggingWebConnection.class);
080:
081: private int counter_;
082: private final WebConnection wrappedWebConnection_;
083: private final String reportBaseName_;
084: private final File javaScriptFile_;
085:
086: /**
087: * Wraps a web connection to have a report generated of the received responses.
088: * @param webConnection the webConnection that do the real work
089: * @param reportBaseName the base name to use for the generated files.
090: * The report will be reportBaseName + ".html" in the temp file.
091: * @throws IOException in case of problems writing the files.
092: */
093: public DebuggingWebConnection(final WebConnection webConnection,
094: final String reportBaseName) throws IOException {
095:
096: super (webConnection);
097:
098: wrappedWebConnection_ = webConnection;
099: reportBaseName_ = reportBaseName;
100: javaScriptFile_ = File.createTempFile(reportBaseName_, ".js");
101: createOverview();
102: }
103:
104: /**
105: * Calls the wrapped webconnection and save the received response.
106: * {@inheritDoc}
107: */
108: public WebResponse getResponse(
109: final WebRequestSettings webRequestSettings)
110: throws IOException {
111: final WebResponse response = wrappedWebConnection_
112: .getResponse(webRequestSettings);
113: saveResponse(response, webRequestSettings);
114: return response;
115: }
116:
117: /**
118: * Save the response content in the temp dir and add it to the summary page
119: * @param response the response to save
120: * @param settings the settings used to get the response
121: * @throws IOException if a problem occurs writing the file
122: */
123: protected void saveResponse(final WebResponse response,
124: final WebRequestSettings settings) throws IOException {
125: counter_++;
126: final String extension;
127: if ("application/x-javascript"
128: .equals(response.getContentType())) {
129: extension = ".js";
130: } else if ("text/html".equals(response.getContentType())) {
131: extension = ".html";
132: } else {
133: extension = ".txt";
134: }
135: final File f = File.createTempFile(reportBaseName_ + counter_
136: + "-", extension);
137: final String content = response.getContentAsString();
138: FileUtils.writeStringToFile(f, content, response
139: .getContentCharSet());
140: LOG.info("Created file " + f.getAbsolutePath()
141: + " for response " + counter_ + ": "
142: + response.getUrl());
143:
144: final StringBuffer buffer = new StringBuffer();
145: buffer.append("tab[tab.length] = {code: "
146: + response.getStatusCode() + ", ");
147: buffer.append("fileName: '" + f.getName() + "', ");
148: buffer.append("contentType: '" + response.getContentType()
149: + "', ");
150: buffer.append("method: '"
151: + settings.getSubmitMethod().getName() + "', ");
152: buffer.append("url: '" + response.getUrl() + "', ");
153: buffer.append("headers: "
154: + nameValueListToJsMap(response.getResponseHeaders()));
155: buffer.append("};\n");
156: final FileWriter jsFileWriter = new FileWriter(javaScriptFile_,
157: true);
158: jsFileWriter.write(buffer.toString());
159:
160: jsFileWriter.close();
161: }
162:
163: /**
164: * Produces a String that will produce a JS map like "{'key1': 'value1', 'key 2': 'value2'}"
165: * @param headers a list of {@link NameValuePair}
166: * @return the JS String
167: */
168: static String nameValueListToJsMap(final List headers) {
169: if (headers == null || headers.isEmpty()) {
170: return "{}";
171: }
172: final StringBuffer buffer = new StringBuffer("{");
173: for (final Iterator iter = headers.iterator(); iter.hasNext();) {
174: final NameValuePair header = (NameValuePair) iter.next();
175: buffer.append("'" + header.getName() + "': '"
176: + header.getValue().replaceAll("'", "\\'") + "', ");
177: }
178: buffer.delete(buffer.length() - 2, buffer.length());
179: buffer.append("}");
180: return buffer.toString();
181: }
182:
183: /**
184: * Creates the summary file and the javascript file that will be updated for each received response
185: * @throws IOException if a problem occurs writing the file
186: */
187: private void createOverview() throws IOException {
188: FileUtils.writeStringToFile(javaScriptFile_, "var tab = [];\n",
189: TextUtil.DEFAULT_CHARSET);
190:
191: final File summary = new File(javaScriptFile_.getParentFile(),
192: reportBaseName_ + ".html");
193: final String content = "<html><head><title>Summary for "
194: + reportBaseName_
195: + "</title>\n"
196: + "<h1>Received responses</h1>\n"
197: + "<script src='"
198: + javaScriptFile_.getName()
199: + "' type='text/javascript'></script>\n"
200: + "</head>\n"
201: + "<body>"
202: + "<ol>\n"
203: + "<script>\n"
204: + "for (var i=0; i<tab.length; i++) {\n"
205: + " var curRes = tab[i];\n"
206: + " document.writeln('<li>'"
207: + " + curRes.code + ' ' + curRes.method + ' ' "
208: + " + '<a href=\"' + curRes.fileName + '\" target=_blank>' + curRes.url + '</a> "
209: + " (' + curRes.contentType + ')</li>');\n" + "}\n"
210: + "</script>\n" + "</ol>" + "</body></html>";
211:
212: FileUtils.writeStringToFile(summary, content,
213: TextUtil.DEFAULT_CHARSET);
214: LOG.info("Summary will be in " + summary.getAbsolutePath());
215: }
216: }
|