/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/component/service/impl/SearchListResponseImpl.java $
* $Id: SearchListResponseImpl.java 105078 2012-02-24 23:00:38Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 org.sakaiproject.search.component.service.impl;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.Query;
import org.sakaiproject.search.api.EntityContentProducer;
import org.sakaiproject.search.api.PortalUrlEnabledProducer;
import org.sakaiproject.search.api.SearchIndexBuilder;
import org.sakaiproject.search.api.SearchList;
import org.sakaiproject.search.api.SearchResult;
import org.sakaiproject.search.api.SearchService;
import org.sakaiproject.search.filter.SearchItemFilter;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* @author ieb
*/
public class SearchListResponseImpl implements SearchList, ContentHandler
{
private static Log log = LogFactory.getLog(SearchListResponseImpl.class);
private Query query;
private int start = 0;
private int end = 500;
private Analyzer analyzer;
private SearchItemFilter filter;
private SearchIndexBuilder searchIndexBuilder;
private SearchService searchService;
private List<SearchResult> resultsList;
private Stack<StackElement> stack;
private Object errorMessage = null;
private int size;
private int fullsize;
public SearchListResponseImpl(String response, Query query, int start,
int end, Analyzer analyzer, SearchItemFilter filter,
SearchIndexBuilder searchIndexBuilder,
SearchService searchService) throws SAXException, IOException
{
this.query = query;
this.start = start;
this.end = end;
this.analyzer = analyzer;
this.filter = filter;
this.searchIndexBuilder = searchIndexBuilder;
this.searchService = searchService;
if (log.isDebugEnabled()) {
log.debug("search response: ["+response+"]");
}
XMLReader xr = XMLReaderFactory.createXMLReader();
xr.setContentHandler(this);
InputSource is = new InputSource(new StringReader(response));
xr.parse(is);
if (errorMessage != null)
{
log
.error("Failed to perform remote request, remote exception was: \n"
+ errorMessage);
throw new IOException("Failed to perform remote request ");
}
}
/**
* @{inheritDoc}
*/
public Iterator<SearchResult> iterator(final int startAt)
{
return new Iterator<SearchResult>()
{
int counter = Math.max(startAt, start) - start;
public boolean hasNext()
{
return counter < resultsList.size();
}
public SearchResult next()
{
int thisHit = counter;
counter++;
if (log.isDebugEnabled())
{
log.debug("Iterator Getting item " + thisHit);
}
SearchResult ret =(SearchResult) resultsList.get(thisHit);
String url = checkUrl(ret.getReference());
if (url != null)
ret.setUrl(url);
return filter.filter(ret);
}
public void remove()
{
throw new UnsupportedOperationException("Not Implemented");
}
/**
* Check the results url before returning
* @param reference
* @return
*/
private String checkUrl(String reference) {
log.debug("checkUrl(" + reference);
if (searchIndexBuilder != null) {
EntityContentProducer ecp = searchIndexBuilder.newEntityContentProducer(reference);
if (ecp == null )
return null;
if (PortalUrlEnabledProducer.class.isAssignableFrom(ecp.getClass()))
return ecp.getUrl(reference);
}
return null;
}
};
}
public int size()
{
return size;
}
public int getFullSize()
{
return fullsize;
}
public boolean isEmpty()
{
return (size() == 0);
}
public boolean contains(Object arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public Iterator<SearchResult> iterator()
{
return iterator(0);
}
public Object[] toArray()
{
Object[] o = new Object[size()];
for (int i = 0; i < o.length; i++)
{
o[i] = filter.filter((SearchResult) resultsList.get(i));
}
return o;
}
public Object[] toArray(Object[] arg0)
{
if (arg0 instanceof SearchResult[])
{
return toArray();
}
return null;
}
public boolean add(SearchResult arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public boolean remove(Object arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public boolean containsAll(Collection arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public boolean addAll(Collection arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public boolean addAll(int arg0, Collection arg1)
{
throw new UnsupportedOperationException("Not Implemented");
}
public boolean removeAll(Collection arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public boolean retainAll(Collection arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public void clear()
{
throw new UnsupportedOperationException("Not Implemented");
}
public SearchResult get(int arg0)
{
SearchResult sr = (SearchResult) resultsList.get(arg0);
String url = checkUrl(sr.getReference());
if (url != null)
sr.setUrl(url);
return filter.filter(sr);
}
public SearchResult set(int arg0, SearchResult arg1)
{
throw new UnsupportedOperationException("Not Implemented");
}
public void add(int arg0, SearchResult arg1)
{
throw new UnsupportedOperationException("Not Implemented");
}
public SearchResult remove(int arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public int indexOf(Object arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public int lastIndexOf(Object arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public ListIterator<SearchResult> listIterator()
{
throw new UnsupportedOperationException("Not Implemented");
}
public ListIterator<SearchResult> listIterator(int arg0)
{
throw new UnsupportedOperationException("Not Implemented");
}
public List<SearchResult> subList(int arg0, int arg1)
{
throw new UnsupportedOperationException("Not Implemented");
}
public int getStart()
{
return start;
}
public void characters(char[] ch, int start, int length)
throws SAXException
{
StackElement se = (StackElement) stack.peek();
se.append(ch, start, length);
}
public void endDocument() throws SAXException
{
}
public void endElement(String uri, String localName, String qName)
throws SAXException
{
if (log.isDebugEnabled())
{
log.debug("End Element uri:" + uri + " ln:" + localName + " qn:"
+ qName);
}
StackElement se = (StackElement) stack.pop();
if ("error".equals(localName))
{
errorMessage = se.getContent();
log.error("Error Message found from remote search " + errorMessage);
}
else if ("result".equals(localName))
{
SearchResult sr;
try
{
sr = new SearchResultResponseImpl(se.getAttributes(), query,
analyzer, searchIndexBuilder,
searchService);
}
catch (IOException e)
{
throw new SAXException(e.getMessage(), e);
}
resultsList.add(sr);
if (log.isDebugEnabled())
{
log.debug("Added Search Result " + resultsList.size());
}
}
else if ("results".equals(localName))
{
fullsize = Integer
.parseInt(se.getAttributes().getValue("fullsize"));
start = Integer.parseInt(se.getAttributes().getValue("start"));
size = Integer.parseInt(se.getAttributes().getValue("size"));
}
}
public void endPrefixMapping(String prefix) throws SAXException
{
}
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException
{
}
public void processingInstruction(String target, String data)
throws SAXException
{
}
public void setDocumentLocator(Locator locator)
{
}
public void skippedEntity(String name) throws SAXException
{
}
public void startDocument() throws SAXException
{
resultsList = new ArrayList<SearchResult>();
stack = new Stack<StackElement>();
}
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException
{
if (log.isDebugEnabled())
{
log.debug("Start Element uri:" + uri + " ln:" + localName + " qn:"
+ qName);
}
StackElement se = new StackElement(uri, localName, qName, atts);
stack.push(se);
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException
{
}
public class StackElement
{
private String uri;
private String localName;
private String name;
private Attributes atts;
private StringBuilder content;
public StackElement(String uri, String localName, String name,
Attributes atts)
{
this.uri = uri;
this.localName = localName;
this.name = name;
this.atts = new AttributesImpl(atts);
this.content = new StringBuilder();
}
public Attributes getAttributes()
{
return atts;
}
public String getContent()
{
return content.toString();
}
public void append(char[] ch, int start, int length)
{
content.append(ch, start, length);
}
}
/**
* Check the results url before returning
* @param reference
* @return
*/
private String checkUrl(String reference) {
if (searchIndexBuilder != null) {
EntityContentProducer ecp = searchIndexBuilder.newEntityContentProducer(reference);
if (ecp == null )
return null;
;
if (PortalUrlEnabledProducer.class.isAssignableFrom(ecp.getClass()))
return ecp.getUrl(reference);
}
return null;
}
}