/**********************************************************************************
*
* Copyright (c) 2003, 2004, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package edu.indiana.lib.twinpeaks.search;
import edu.indiana.lib.twinpeaks.util.*;
import org.osid.repository.AssetIterator;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.w3c.dom.html.*;
import org.xml.sax.*;
/**
* Result rendering - base class and helpers
*/
public abstract class SearchResultBase implements SearchResultInterface
{
private static org.apache.commons.logging.Log _log = LogUtils.getLog(SearchResultBase.class);
/**
* Parse the search engine response and expose pertinent results
*/
private ArrayList _itemList;
private AssetIterator _assetIterator;
private int _start;
private int _count;
private String _nextPreviewPage;
private String _previousPreviewPage;
protected String _searchQuery;
protected byte _searchResponseBytes[];
protected String _searchResponseString;
protected Document _searchResponseDocument;
protected String _database;
protected String _sessionId;
protected String _baseUrl;
/**
* Constructor
*/
public SearchResultBase() {
super();
}
/*
* Interface methods
*/
/**
* Save various attributes of the general search request
* @param query The QueryBase extension that sent the search request
*/
public void initialize(QueryBase query)
{
_searchQuery = query.getRequestParameter("searchString");
_database = query.getRequestParameter("database");
_sessionId = query.getRequestParameter("guid");
_searchResponseString = query.getResponseString();
_searchResponseBytes = query.getResponseBytes();
_searchResponseDocument = parseResponse();
_itemList = new ArrayList();
_start = 1;
saveBaseUrl(query.getUrl());
}
/**
* Add a MatchItem object
* @param item MatchItem to add
*/
public void addItem(MatchItem item) {
_itemList.add(item);
}
/**
* Fetch the original query text
* @return Search string
*/
public String getQuery() {
return _searchQuery;
}
/**
* Return the starting item number for this search (one based)
* @return Starting item number
*/
public int getSearchStart() {
return _start;
}
/**
* Set the starting item number for this search (one based)
* @param start Starting item number
*/
public void setSearchStart(int start) {
_start = start;
}
/**
* Set the starting item number for this search (one based)
* @param start Starting item number
*/
public void setSearchStart(String start) {
try {
_start = Integer.parseInt(start);
} catch (NumberFormatException exception) {
_log.warn("Invalid number format: " + start);
return;
}
}
/**
* Return the count of matching items returned
* @return Item count
*/
public int getMatchCount() {
return _itemList.size();
}
/**
* Fetch the "next preview page" reference (used to paginate results
* null if none)
* @return Next page reference
*/
public String getNextPreviewPage() {
return _nextPreviewPage;
}
/**
* Set the "next preview page" reference
* @param reference Next page reference
*/
public void setNextPreviewPage(String reference) {
_nextPreviewPage = reference;
}
/**
* Fetch the "previous preview page" reference (used to paginate results,
* null if none)
* @return Previous page reference
*/
public String getPreviousPreviewPage() {
return _previousPreviewPage;
}
/**
* Set the "previous preview page" reference
* @param reference Previous page reference
*/
public void setPreviousPreviewPage(String reference) {
_previousPreviewPage = reference;
}
/**
* Can this display be paginated (next/previous pages for display)?
* @return true if so
*/
public boolean canPaginate() {
return (_previousPreviewPage != null) || (_nextPreviewPage != null);
}
/**
* Get an iterator to the result list
* @return SearchResult Iterator
*/
public Iterator iterator() {
return _itemList.iterator();
}
/**
* Return the MatchItem list as a simple array
* @return MatchItem array
*/
public MatchItem[] toArray() {
return (MatchItem[]) _itemList.toArray(new MatchItem[_itemList.size()]);
}
/**
* Return search results as a String
* @return Result Document
*/
public String getSearchResponseString() {
return _searchResponseString;
}
/*
* Helpers
*/
/**
* Return search results as a Document
* @return Result Document
*/
public Document getSearchResponseDocument() {
return _searchResponseDocument;
}
/**
* Parse the search engine response as HTML.
* See <code>initialize()</code> (override as reqired)
* @return Response as a DOM Document
*/
protected Document parseResponse() throws SearchException {
try {
return DomUtils.parseHtmlBytes(_searchResponseBytes);
} catch (Exception exception) {
throw new SearchException(exception.toString());
}
}
/**
* Save the request URL base (the server portion only)
* @param url Request URL (with or without parameters)
*/
public void saveBaseUrl(String url) {
_baseUrl = HttpTransactionUtils.getServer(url);
}
/**
* Form a full URL (protocol, server, arguments) from a base URL and
* provided parameters
* @param baseUrl The base (or template) URL
* @param urlFragment The (possibly) relative URL to be combined with the base
* @return A full URL (as a String)
*/
public String getFullUrl(String baseUrl, String urlFragment) {
String thisUrl = baseUrl;
if (thisUrl == null) {
thisUrl = _baseUrl;
}
if (thisUrl != null) {
try {
URL base = new URL(thisUrl);
return new URL(base, urlFragment).toString();
} catch (MalformedURLException exception) {
throw new SearchException(exception.toString());
}
}
return urlFragment;
}
/**
* Form a full URL (protocol, server, arguments) from a provided URL
* and a previously provided base URL
* @param urlFragment The (possibly) relative URL to be combined with the base
* @return A full URL (as a String)
*/
public String getFullUrl(String urlFragment) {
return getFullUrl(null, urlFragment);
}
/**
* Prepend proxy string (if not already present)
* @param url Target URL
* @param proxy Proxy specification
* @return (Possibly) updated URL string
*/
public String prependProxy(String url, String proxy) {
StringBuilder fullUrl;
_log.debug("prependProxy: proxy [" + proxy + "] vs. [" + url + "]");
if (StringUtils.isNull(proxy)) {
return url;
}
if (url.startsWith(proxy)) {
return url;
}
fullUrl = new StringBuilder(proxy);
fullUrl.append(url);
return fullUrl.toString();
}
/**
* Verify we have the expected number of Elements in a Node list
* @param nodeList List of collected Elements
* @param expected Number of Elements we expect to see
* @return true If we have the expected number Elements
*/
public boolean expectedNodeCount(NodeList nodeList, int expected) {
String tag;
int length;
if ((length = nodeList.getLength()) == expected) {
return true;
}
tag = "Element";
if (length > 0) {
tag = nodeList.item(0).getNodeName();
}
_log.debug("Unexpected "
+ tag
+ " count: "
+ length
+ " (ignoring entry)");
return false;
}
/**
* Locate select attribute of the first matching image
* @param parent Parent element (look here for IMG tag)
* @param name Attribute name (src, alt, etc)
* @return Image name value (null if none)
*/
public String getImageAttribute(Element parent, String name) {
Element image;
String value;
if ((image = DomUtils.getElement(parent, "IMG")) == null) {
return null;
}
value = image.getAttribute(name);
return StringUtils.isNull(value) ? null : value;
}
}