001: /********************************************************************************************************************
002: * $Id: WebRequestSource.java,v 1.43 2004/10/29 00:41:24 russgold Exp $
003: *
004: * Copyright (c) 2001-2004, Russell Gold
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
007: * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
008: * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
009: * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in all copies or substantial portions
012: * of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
015: * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
016: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
017: * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
018: * DEALINGS IN THE SOFTWARE.
019: *
020: *******************************************************************************************************************/package com.meterware.httpunit;
021:
022: import org.w3c.dom.Node;
023: import org.w3c.dom.Element;
024: import org.xml.sax.SAXException;
025:
026: import java.net.URL;
027: import java.util.StringTokenizer;
028: import java.io.IOException;
029:
030: /**
031: * Base class for objects which can be clicked to generate new web requests.
032: *
033: * @author <a href="mailto:russgold@httpunit.org">Russell Gold</a>
034: */
035: abstract public class WebRequestSource extends ParameterHolder
036: implements HTMLElement {
037:
038: private FrameSelector _frame;
039:
040: /**
041: * Returns the ID associated with this request source.
042: **/
043: public String getID() {
044: return getAttribute("id");
045: }
046:
047: /**
048: * Returns the class associated with this request source.
049: **/
050: public String getClassName() {
051: return getAttribute("class");
052: }
053:
054: /**
055: * Returns the name associated with this request source.
056: **/
057: public String getName() {
058: return getAttribute("name");
059: }
060:
061: /**
062: * Returns the title associated with this request source.
063: **/
064: public String getTitle() {
065: return getAttribute("title");
066: }
067:
068: /**
069: * Returns the target for this request source.
070: */
071: public String getTarget() {
072: if (getSpecifiedTarget().length() == 0) {
073: return _defaultTarget;
074: } else {
075: return getSpecifiedTarget();
076: }
077: }
078:
079: /**
080: * Returns the name of the frame containing this request source.
081: * @deprecated as of 1.6, use #getFrame
082: */
083: public String getPageFrame() {
084: return _frame.getName();
085: }
086:
087: /**
088: * Returns the frame containing this request source.
089: */
090: public FrameSelector getFrame() {
091: return _frame;
092: }
093:
094: /**
095: * Returns the fragment identifier for this request source, used to identifier an element within an HTML document.
096: */
097: public String getFragmentIdentifier() {
098: final int hashIndex = getDestination().indexOf('#');
099: if (hashIndex < 0) {
100: return "";
101: } else {
102: return getDestination().substring(hashIndex + 1);
103: }
104: }
105:
106: /**
107: * Returns a copy of the domain object model subtree associated with this entity.
108: **/
109: public Node getDOMSubtree() {
110: return _node.cloneNode( /* deep */true);
111: }
112:
113: /**
114: * Creates and returns a web request from this request source.
115: **/
116: abstract public WebRequest getRequest();
117:
118: /**
119: * Returns an array containing the names of any parameters to be sent on a request based on this request source.
120: **/
121: abstract public String[] getParameterNames();
122:
123: /**
124: * Returns the values of the named parameter.
125: **/
126: abstract public String[] getParameterValues(String name);
127:
128: /**
129: * Returns the URL relative to the current page which will handle the request.
130: */
131: String getRelativePage() {
132: final String url = getRelativeURL();
133: if (HttpUnitUtils.isJavaScriptURL(url))
134: return url;
135: final int questionMarkIndex = url.indexOf("?");
136: if (questionMarkIndex >= 1
137: && questionMarkIndex < url.length() - 1) {
138: return url.substring(0, questionMarkIndex);
139: }
140: return url;
141: }
142:
143: protected String getRelativeURL() {
144: String result = HttpUnitUtils.trimAll(HttpUnitUtils
145: .trimFragment(getDestination()));
146: if (result.trim().length() == 0)
147: result = getBaseURL().getFile();
148: return result;
149: }
150:
151: //----------------------------- protected members ---------------------------------------------
152:
153: /**
154: * Contructs a web request source.
155: * @param response the response from which this request source was extracted
156: * @param node the DOM subtree defining this request source
157: * @param baseURL the URL on which to base all releative URL requests
158: * @param destination the relative URL to which requests will be directed
159: **/
160: WebRequestSource(WebResponse response, Node node, URL baseURL,
161: String destination, FrameSelector frame,
162: String defaultTarget) {
163: if (node == null)
164: throw new IllegalArgumentException("node must not be null");
165: _baseResponse = response;
166: _node = node;
167: _baseURL = baseURL;
168: _destination = destination;
169: _frame = frame;
170: _defaultTarget = defaultTarget;
171: }
172:
173: protected URL getBaseURL() {
174: return _baseURL;
175: }
176:
177: protected String getDestination() {
178: return _destination;
179: }
180:
181: protected void setDestination(String destination) {
182: _destination = destination;
183: }
184:
185: /**
186: * Returns the actual DOM for this request source, not a copy.
187: **/
188: protected Node getNode() {
189: return _node;
190: }
191:
192: /**
193: * Returns the HTMLPage associated with this request source.
194: */
195: protected HTMLPage getHTMLPage() throws SAXException {
196: return _baseResponse.getReceivedPage();
197: }
198:
199: /**
200: * Extracts any parameters specified as part of the destination URL, calling addPresetParameter for each one
201: * in the order in which they are found.
202: */
203: final protected void loadDestinationParameters() {
204: StringTokenizer st = new StringTokenizer(getParametersString(),
205: PARAM_DELIM);
206: while (st.hasMoreTokens())
207: stripOneParameter(st.nextToken());
208: }
209:
210: protected WebResponse submitRequest(String event,
211: final WebRequest request) throws IOException, SAXException {
212: WebResponse response = null;
213: if (event.length() == 0
214: || getScriptableDelegate().doEvent(event))
215: response = submitRequest(request);
216: if (response == null)
217: response = getCurrentFrameContents();
218: return response;
219: }
220:
221: protected WebResponse getCurrentFrameContents() {
222: return getCurrentFrame(getBaseResponse().getWindow(), _frame);
223: }
224:
225: private WebResponse getCurrentFrame(WebWindow window,
226: FrameSelector pageFrame) {
227: return window.hasFrame(pageFrame) ? window
228: .getFrameContents(pageFrame) : window.getCurrentPage();
229: }
230:
231: /**
232: * Submits a request to the web client from which this request source was originally obtained.
233: **/
234: final protected WebResponse submitRequest(WebRequest request)
235: throws IOException, SAXException {
236: return getDestination().equals("#") ? _baseResponse
237: : _baseResponse.getWindow().sendRequest(request);
238: }
239:
240: /**
241: * Returns the web response containing this request source.
242: */
243: final protected WebResponse getBaseResponse() {
244: return _baseResponse;
245: }
246:
247: /**
248: * Records a parameter defined by including it in the destination URL.
249: * The value can be null, if the parameter name was not specified with an equals sign.
250: **/
251: abstract protected void addPresetParameter(String name, String value);
252:
253: public String getAttribute(final String name) {
254: return NodeUtils.getNodeAttribute(_node, name);
255: }
256:
257: public boolean isSupportedAttribute(String name) {
258: return false;
259: }
260:
261: /**
262: * Returns the text value of this block.
263: **/
264: public String getText() {
265: if (_node.getNodeType() == Node.TEXT_NODE) {
266: return _node.getNodeValue().trim();
267: } else if (_node == null || !_node.hasChildNodes()) {
268: return "";
269: } else {
270: return NodeUtils.asText(_node.getChildNodes()).trim();
271: }
272: }
273:
274: public String getTagName() {
275: return _node.getNodeName();
276: }
277:
278: String getAttribute(final String name, String defaultValue) {
279: return NodeUtils.getNodeAttribute(_node, name, defaultValue);
280: }
281:
282: //----------------------------- private members -----------------------------------------------
283:
284: private static final String PARAM_DELIM = "&";
285:
286: /** The web response containing this request source. **/
287: private WebResponse _baseResponse;
288:
289: /** The name of the frame in which the response containing this request source is rendered. **/
290: private String _defaultTarget;
291:
292: /** The URL of the page containing this entity. **/
293: private URL _baseURL;
294:
295: /** The raw destination specified for the request, including anchors and parameters. **/
296: private String _destination;
297:
298: /** The DOM node representing this entity. **/
299: private Node _node;
300:
301: private String getSpecifiedTarget() {
302: return getAttribute("target");
303: }
304:
305: protected void setTargetAttribute(String value) {
306: ((Element) _node).setAttribute("target", value);
307: }
308:
309: /**
310: * Gets all parameters from a URL
311: **/
312: private String getParametersString() {
313: String url = HttpUnitUtils.trimFragment(getDestination());
314: if (url.trim().length() == 0)
315: url = getBaseURL().toExternalForm();
316: if (HttpUnitUtils.isJavaScriptURL(url))
317: return "";
318: final int questionMarkIndex = url.indexOf("?");
319: if (questionMarkIndex >= 1
320: && questionMarkIndex < url.length() - 1) {
321: return url.substring(questionMarkIndex + 1);
322: }
323: return "";
324: }
325:
326: /**
327: * Extracts a parameter of the form <name>[=[<value>]].
328: **/
329: private void stripOneParameter(String param) {
330: final int index = param.indexOf("=");
331: String value = ((index < 0) ? null
332: : ((index == param.length() - 1) ? getEmptyParameterValue()
333: : decode(param.substring(index + 1))));
334: String name = (index < 0) ? decode(param) : decode(param
335: .substring(0, index));
336: addPresetParameter(name, value);
337: }
338:
339: private String decode(String string) {
340: return HttpUnitUtils.decode(string,
341: _baseResponse.getCharacterSet()).trim();
342: }
343:
344: abstract protected String getEmptyParameterValue();
345:
346: }
|