001: /**********************************************************************************
002: *
003: * Copyright (c) 2003, 2004 The Regents of the University of Michigan, Trustees of Indiana University,
004: * Board of Trustees of the Leland Stanford, Jr., University, and The MIT Corporation
005: *
006: * Licensed under the Educational Community License Version 1.0 (the "License");
007: * By obtaining, using and/or copying this Original Work, you agree that you have read,
008: * understand, and will comply with the terms and conditions of the Educational Community License.
009: * You may obtain a copy of the License at:
010: *
011: * http://cvs.sakaiproject.org/licenses/license_1_0.html
012: *
013: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
014: * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
015: * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
016: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
017: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
018: *
019: **********************************************************************************/package edu.indiana.lib.twinpeaks.search;
020:
021: import edu.indiana.lib.twinpeaks.util.*;
022:
023: import org.osid.repository.AssetIterator;
024:
025: import java.io.*;
026: import java.net.*;
027: import java.util.*;
028:
029: import javax.xml.parsers.*;
030:
031: import org.w3c.dom.*;
032: import org.w3c.dom.html.*;
033: import org.xml.sax.*;
034:
035: /**
036: * Result rendering - base class and helpers
037: */
038: public abstract class SearchResultBase implements SearchResultInterface {
039: private static org.apache.commons.logging.Log _log = LogUtils
040: .getLog(SearchResultBase.class);
041:
042: /**
043: * Parse the search engine response and expose pertinent results
044: */
045: private ArrayList _itemList;
046: private AssetIterator _assetIterator;
047: private int _start;
048: private int _count;
049:
050: private String _nextPreviewPage;
051: private String _previousPreviewPage;
052:
053: protected String _searchQuery;
054: protected byte _searchResponseBytes[];
055: protected String _searchResponseString;
056: protected Document _searchResponseDocument;
057: protected String _database;
058:
059: protected String _sessionId;
060: protected String _baseUrl;
061:
062: /**
063: * Constructor
064: */
065: public SearchResultBase() {
066: super ();
067: }
068:
069: /*
070: * Interface methods
071: */
072:
073: /**
074: * Save various attributes of the general search request
075: * @param query The QueryBase extension that sent the search request
076: */
077: public void initialize(QueryBase query) {
078: _searchQuery = query.getRequestParameter("searchString");
079: _database = query.getRequestParameter("database");
080: _sessionId = query.getRequestParameter("guid");
081: _searchResponseString = query.getResponseString();
082: _searchResponseBytes = query.getResponseBytes();
083: _searchResponseDocument = parseResponse();
084:
085: _itemList = new ArrayList();
086: _start = 1;
087:
088: saveBaseUrl(query.getUrl());
089: }
090:
091: /**
092: * Add a MatchItem object
093: * @param item MatchItem to add
094: */
095: public void addItem(MatchItem item) {
096: _itemList.add(item);
097: }
098:
099: /**
100: * Fetch the original query text
101: * @return Search string
102: */
103: public String getQuery() {
104: return _searchQuery;
105: }
106:
107: /**
108: * Return the starting item number for this search (one based)
109: * @return Starting item number
110: */
111: public int getSearchStart() {
112: return _start;
113: }
114:
115: /**
116: * Set the starting item number for this search (one based)
117: * @param start Starting item number
118: */
119: public void setSearchStart(int start) {
120: _start = start;
121: }
122:
123: /**
124: * Set the starting item number for this search (one based)
125: * @param start Starting item number
126: */
127: public void setSearchStart(String start) {
128: try {
129: _start = Integer.parseInt(start);
130: } catch (NumberFormatException exception) {
131: _log.warn("Invalid number format: " + start);
132: return;
133: }
134: }
135:
136: /**
137: * Return the count of matching items returned
138: * @return Item count
139: */
140: public int getMatchCount() {
141: return _itemList.size();
142: }
143:
144: /**
145: * Fetch the "next preview page" reference (used to paginate results
146: * null if none)
147: * @return Next page reference
148: */
149: public String getNextPreviewPage() {
150: return _nextPreviewPage;
151: }
152:
153: /**
154: * Set the "next preview page" reference
155: * @param reference Next page reference
156: */
157: public void setNextPreviewPage(String reference) {
158: _nextPreviewPage = reference;
159: }
160:
161: /**
162: * Fetch the "previous preview page" reference (used to paginate results,
163: * null if none)
164: * @return Previous page reference
165: */
166: public String getPreviousPreviewPage() {
167: return _previousPreviewPage;
168: }
169:
170: /**
171: * Set the "previous preview page" reference
172: * @param reference Previous page reference
173: */
174: public void setPreviousPreviewPage(String reference) {
175: _previousPreviewPage = reference;
176: }
177:
178: /**
179: * Can this display be paginated (next/previous pages for display)?
180: * @return true if so
181: */
182: public boolean canPaginate() {
183: return (_previousPreviewPage != null)
184: || (_nextPreviewPage != null);
185: }
186:
187: /**
188: * Get an iterator to the result list
189: * @return SearchResult Iterator
190: */
191: public Iterator iterator() {
192: return _itemList.iterator();
193: }
194:
195: /**
196: * Return the MatchItem list as a simple array
197: * @return MatchItem array
198: */
199: public MatchItem[] toArray() {
200: return (MatchItem[]) _itemList.toArray(new MatchItem[_itemList
201: .size()]);
202: }
203:
204: /**
205: * Return search results as a String
206: * @return Result Document
207: */
208: public String getSearchResponseString() {
209: return _searchResponseString;
210: }
211:
212: /*
213: * Helpers
214: */
215:
216: /**
217: * Return search results as a Document
218: * @return Result Document
219: */
220: public Document getSearchResponseDocument() {
221: return _searchResponseDocument;
222: }
223:
224: /**
225: * Parse the search engine response as HTML.
226: * See <code>initialize()</code> (override as reqired)
227: * @return Response as a DOM Document
228: */
229: protected Document parseResponse() throws SearchException {
230: try {
231: return DomUtils.parseHtmlBytes(_searchResponseBytes);
232: } catch (Exception exception) {
233: throw new SearchException(exception.toString());
234: }
235: }
236:
237: /**
238: * Save the request URL base (the server portion only)
239: * @param url Request URL (with or without parameters)
240: */
241: public void saveBaseUrl(String url) {
242: _baseUrl = HttpTransactionUtils.getServer(url);
243: }
244:
245: /**
246: * Form a full URL (protocol, server, arguments) from a base URL and
247: * provided parameters
248: * @param baseUrl The base (or template) URL
249: * @param urlFragment The (possibly) relative URL to be combined with the base
250: * @return A full URL (as a String)
251: */
252: public String getFullUrl(String baseUrl, String urlFragment) {
253: String this Url = baseUrl;
254:
255: if (this Url == null) {
256: this Url = _baseUrl;
257: }
258:
259: if (this Url != null) {
260: try {
261: URL base = new URL(this Url);
262:
263: return new URL(base, urlFragment).toString();
264:
265: } catch (MalformedURLException exception) {
266: throw new SearchException(exception.toString());
267: }
268: }
269: return urlFragment;
270: }
271:
272: /**
273: * Form a full URL (protocol, server, arguments) from a provided URL
274: * and a previously provided base URL
275: * @param urlFragment The (possibly) relative URL to be combined with the base
276: * @return A full URL (as a String)
277: */
278: public String getFullUrl(String urlFragment) {
279: return getFullUrl(null, urlFragment);
280: }
281:
282: /**
283: * Prepend proxy string (if not already present)
284: * @param url Target URL
285: * @param proxy Proxy specification
286: * @return (Possibly) updated URL string
287: */
288: public String prependProxy(String url, String proxy) {
289: StringBuffer fullUrl;
290:
291: _log.debug("prependProxy: proxy [" + proxy + "] vs. [" + url
292: + "]");
293:
294: if (StringUtils.isNull(proxy)) {
295: return url;
296: }
297:
298: if (url.startsWith(proxy)) {
299: return url;
300: }
301:
302: fullUrl = new StringBuffer(proxy);
303: fullUrl.append(url);
304:
305: return fullUrl.toString();
306: }
307:
308: /**
309: * Verify we have the expected number of Elements in a Node list
310: * @param nodeList List of collected Elements
311: * @param expected Number of Elements we expect to see
312: * @return true If we have the expected number Elements
313: */
314: public boolean expectedNodeCount(NodeList nodeList, int expected) {
315: String tag;
316: int length;
317:
318: if ((length = nodeList.getLength()) == expected) {
319: return true;
320: }
321:
322: tag = "Element";
323:
324: if (length > 0) {
325: tag = nodeList.item(0).getNodeName();
326: }
327:
328: _log.debug("Unexpected " + tag + " count: " + length
329: + " (ignoring entry)");
330: return false;
331: }
332:
333: /**
334: * Locate select attribute of the first matching image
335: * @param parent Parent element (look here for IMG tag)
336: * @param name Attribute name (src, alt, etc)
337: * @return Image name value (null if none)
338: */
339: public String getImageAttribute(Element parent, String name) {
340: Element image;
341: String value;
342:
343: if ((image = DomUtils.getElement(parent, "IMG")) == null) {
344: return null;
345: }
346:
347: value = image.getAttribute(name);
348: return StringUtils.isNull(value) ? null : value;
349: }
350: }
|