/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/component/service/impl/SearchResultImpl.java $ * $Id: SearchResultImpl.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.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.zip.DataFormatException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.CompressionTools; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.Fieldable; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.InvalidTokenOffsetsException; import org.apache.lucene.search.highlight.QueryScorer; import org.apache.lucene.search.highlight.Scorer; import org.apache.lucene.search.highlight.SimpleHTMLEncoder; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; import org.sakaiproject.search.api.EntityContentProducer; import org.sakaiproject.search.api.PortalUrlEnabledProducer; import org.sakaiproject.search.api.SearchIndexBuilder; import org.sakaiproject.search.api.SearchResult; import org.sakaiproject.search.api.SearchService; import org.sakaiproject.search.api.StoredDigestContentProducer; import org.sakaiproject.search.api.TermFrequency; import org.sakaiproject.search.component.Messages; import org.sakaiproject.search.util.DigestStorageUtil; /** * @author ieb */ public class SearchResultImpl implements SearchResult { private static Log log = LogFactory.getLog(SearchResultImpl.class); private TopDocs topDocs; private int index; private Document doc; String[] fieldNames = null; private Query query = null; private Analyzer analyzer = null; private SearchIndexBuilder searchIndexBuilder; private SearchService searchService; private String url; public SearchResultImpl(TopDocs topDocs, Document doc, int index, Query query, Analyzer analyzer, SearchIndexBuilder searchIndexBuilder, SearchService searchService) throws IOException { this.topDocs = topDocs; this.index = index; this.doc = doc; this.query = query; this.analyzer = analyzer; this.searchIndexBuilder = searchIndexBuilder; this.searchService = searchService; } public float getScore() { ScoreDoc scoreDoc = topDocs.scoreDocs[index]; return scoreDoc.score; } public String getId() { return getReference(); } public String[] getFieldNames() { if (fieldNames != null) { return fieldNames; } HashMap<String, Field> al = new HashMap<String, Field>(); List<Fieldable> e = doc.getFields(); for (int i =0 ; i < e.size(); i++) { Field f = (Field) e.get(i); al.put(f.name(), f); } fieldNames = new String[al.size()]; int ii = 0; for (Iterator<String> i = al.keySet().iterator(); i.hasNext();) { fieldNames[ii++] = (String) i.next(); } return fieldNames; } public String[] getValues(String fieldName) { return doc.getValues(fieldName); } /** * {@inheritDoc} */ public Map<String, String[]> getValueMap() { Map<String, String[]> hm = new HashMap<String, String[]>(); String[] fieldNames = getFieldNames(); for (int i = 0; i < fieldNames.length; i++) { hm.put(fieldNames[i], doc.getValues(fieldNames[i])); } return hm; } public String getUrl() { if (url == null) try { url = CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_URL)); } catch (DataFormatException e) { url = doc.get(SearchService.FIELD_URL); } return url; } public String getTitle() { try { return CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_TITLE)); } catch (DataFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } return doc.get(SearchService.FIELD_TITLE); } public String getTool() { try { return CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_TOOL)); } catch (DataFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } return doc.get(SearchService.FIELD_TOOL); } public int getIndex() { return index; } public String getSearchResult() { try { Scorer scorer = new QueryScorer(query); Highlighter hightlighter = new Highlighter(new SimpleHTMLFormatter(), new SimpleHTMLEncoder(), scorer); StringBuilder sb = new StringBuilder(); // contents no longer contains the digested contents, so we need to // fetch it from the EntityContentProducer byte[][] references = doc.getBinaryValues(SearchService.FIELD_REFERENCE); DigestStorageUtil digestStorageUtil = new DigestStorageUtil(searchService); if (references != null && references.length > 0) { for (int i = 0; i < references.length; i++) { EntityContentProducer sep = searchIndexBuilder .newEntityContentProducer(CompressionTools.decompressString(references[i])); if ( sep != null ) { //does this ecp store on the FS? if (sep instanceof StoredDigestContentProducer) { String digestCount = doc.get(SearchService.FIELD_DIGEST_COUNT); if (digestCount == null) { digestCount = "1"; } log.debug("This file possibly has FS digests with index of " + digestCount); StringBuilder sb1 = digestStorageUtil.getFileContents(CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_REFERENCE)), digestCount); if (sb1.length() > 0) { sb.append(sb1); } else { String digest = sep.getContent(CompressionTools.decompressString(references[i])); sb.append(digest); //we need to save this digestStorageUtil.saveContentToStore(CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_REFERENCE)), sb.toString(), 1); } } else { sb.append(CompressionTools.decompressString(references[i])); } } } } String text = sb.toString(); TokenStream tokenStream = analyzer.tokenStream( SearchService.FIELD_CONTENTS, new StringReader(text)); return hightlighter.getBestFragments(tokenStream, text, 5, " ... "); //$NON-NLS-1$ } catch (IOException e) { return Messages.getString("SearchResultImpl.2") + e.getMessage(); //$NON-NLS-1$ } catch (InvalidTokenOffsetsException e) { return Messages.getString("SearchResultResponseImpl.11") + e.getMessage(); } catch (DataFormatException e) { e.printStackTrace(); return Messages.getString("SearchResultResponseImpl.11") + e.getMessage(); } } public String getReference() { try { String ret = CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_REFERENCE)); log.debug("returning " + ret); return ret; } catch (DataFormatException e) { return doc.get(SearchService.FIELD_REFERENCE); } } public TermFrequency getTerms() throws IOException { ScoreDoc scoreDoc = topDocs.scoreDocs[index]; return searchService.getTerms(scoreDoc.doc); } public void toXMLString(StringBuilder sb) { sb.append("<result"); //$NON-NLS-1$ sb.append(" index=\"").append(getIndex()).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(" score=\"").append(getScore()).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(" sid=\"").append(StringEscapeUtils.escapeXml(getId())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(" site=\"").append(StringEscapeUtils.escapeXml(getSiteId())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(" reference=\"").append(StringEscapeUtils.escapeXml(getReference())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ try { sb.append(" title=\"").append( //$NON-NLS-1$ new String(Base64.encodeBase64(getTitle().getBytes("UTF-8")),"UTF-8")).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } catch (UnsupportedEncodingException e) { sb.append(" title=\"").append(StringEscapeUtils.escapeXml(getTitle())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ } sb.append(" tool=\"").append(StringEscapeUtils.escapeXml(getTool())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ sb.append(" url=\"").append(StringEscapeUtils.escapeXml(getUrl())).append("\" />"); //$NON-NLS-1$ //$NON-NLS-2$ } public String getSiteId() { try { return CompressionTools.decompressString(doc.getBinaryValue(SearchService.FIELD_SITEID)); } catch (DataFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } return doc.get(SearchService.FIELD_SITEID); } public boolean isCensored() { return false; } public void setUrl(String newUrl) { url = newUrl; } public boolean hasPortalUrl() { log.debug("hasPortalUrl(" + getReference()); EntityContentProducer sep = searchIndexBuilder .newEntityContentProducer(getReference()); if (sep != null) { log.debug("got ECP for " + getReference()); if (PortalUrlEnabledProducer.class.isAssignableFrom(sep.getClass())) { log.debug("has portalURL!"); return true; } } return false; } }