001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/search/tags/sakai_2-4-1/search-impl/impl/src/java/org/sakaiproject/search/component/service/impl/SearchResultImpl.java $
003: * $Id: SearchResultImpl.java 22609 2007-03-14 19:28:42Z ian@caret.cam.ac.uk $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.search.component.service.impl;
021:
022: import java.io.IOException;
023: import java.io.StringReader;
024: import java.io.UnsupportedEncodingException;
025: import java.util.Enumeration;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029:
030: import org.apache.commons.codec.binary.Base64;
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.apache.lucene.analysis.Analyzer;
034: import org.apache.lucene.analysis.TokenStream;
035: import org.apache.lucene.document.Document;
036: import org.apache.lucene.document.Field;
037: import org.apache.lucene.search.Hits;
038: import org.apache.lucene.search.Query;
039: import org.apache.lucene.search.highlight.Highlighter;
040: import org.apache.lucene.search.highlight.QueryScorer;
041: import org.apache.lucene.search.highlight.Scorer;
042: import org.sakaiproject.search.api.EntityContentProducer;
043: import org.sakaiproject.search.api.SearchIndexBuilder;
044: import org.sakaiproject.search.api.SearchResult;
045: import org.sakaiproject.search.api.SearchService;
046: import org.sakaiproject.search.api.TermFrequency;
047: import org.sakaiproject.search.component.Messages;
048:
049: /**
050: * @author ieb
051: */
052: public class SearchResultImpl implements SearchResult {
053:
054: private static Log log = LogFactory.getLog(SearchResultImpl.class);
055:
056: private Hits h;
057:
058: private int index;
059:
060: private Document doc;
061:
062: String[] fieldNames = null;
063:
064: private Query query = null;
065:
066: private Analyzer analyzer = null;
067:
068: private SearchIndexBuilder searchIndexBuilder;
069:
070: private SearchService searchService;
071:
072: public SearchResultImpl(Hits h, int index, Query query,
073: Analyzer analyzer, SearchIndexBuilder searchIndexBuilder,
074: SearchService searchService) throws IOException {
075: this .h = h;
076: this .index = index;
077: this .doc = h.doc(index);
078: this .query = query;
079: this .analyzer = analyzer;
080: this .searchIndexBuilder = searchIndexBuilder;
081: this .searchService = searchService;
082: }
083:
084: public float getScore() {
085: try {
086: return h.score(index);
087: } catch (IOException e) {
088: throw new RuntimeException("Cant determine score ", e); //$NON-NLS-1$
089: }
090: }
091:
092: public String getId() {
093: return doc.get(SearchService.FIELD_ID);
094: }
095:
096: public String[] getFieldNames() {
097: if (fieldNames != null) {
098: return fieldNames;
099: }
100: HashMap al = new HashMap();
101: for (Enumeration e = doc.fields(); e.hasMoreElements();) {
102: Field f = (Field) e.nextElement();
103: al.put(f.name(), f);
104: }
105: fieldNames = new String[al.size()];
106: int ii = 0;
107: for (Iterator i = al.keySet().iterator(); i.hasNext();) {
108: fieldNames[ii++] = (String) i.next();
109: }
110: return fieldNames;
111: }
112:
113: public String[] getValues(String fieldName) {
114: return doc.getValues(fieldName);
115: }
116:
117: /**
118: * {@inheritDoc}
119: */
120: public Map getValueMap() {
121: HashMap hm = new HashMap();
122: String[] fieldNames = getFieldNames();
123: for (int i = 0; i < fieldNames.length; i++) {
124: hm.put(fieldNames[i], doc.getValues(fieldNames[i]));
125: }
126: return hm;
127: }
128:
129: public String getUrl() {
130: return doc.get(SearchService.FIELD_URL);
131: }
132:
133: public String getTitle() {
134: return StringUtils.escapeHtml(doc
135: .get(SearchService.FIELD_TITLE), false);
136: }
137:
138: public String getTool() {
139: return StringUtils.escapeHtml(
140: doc.get(SearchService.FIELD_TOOL), false);
141:
142: }
143:
144: public int getIndex() {
145: return index;
146: }
147:
148: public String getSearchResult() {
149: try {
150: Scorer scorer = new QueryScorer(query);
151: Highlighter hightlighter = new Highlighter(scorer);
152: StringBuffer sb = new StringBuffer();
153: // contents no longer contains the digested contents, so we need to
154: // fetch it from the EntityContentProducer
155:
156: String[] references = doc
157: .getValues(SearchService.FIELD_REFERENCE);
158:
159: if (references != null && references.length > 0) {
160:
161: for (int i = 0; i < references.length; i++) {
162: EntityContentProducer sep = searchIndexBuilder
163: .newEntityContentProducer(references[i]);
164: sb.append(sep.getContent(references[i]));
165: }
166: }
167:
168: String text = StringUtils.escapeHtml(sb.toString(), false);
169: TokenStream tokenStream = analyzer.tokenStream(
170: SearchService.FIELD_CONTENTS,
171: new StringReader(text));
172: return hightlighter.getBestFragments(tokenStream, text, 5,
173: " ... "); //$NON-NLS-1$
174: } catch (IOException e) {
175: return Messages.getString("SearchResultImpl.2") + e.getMessage(); //$NON-NLS-1$
176: }
177: }
178:
179: public String getReference() {
180: return doc.get(SearchService.FIELD_REFERENCE);
181: }
182:
183: public TermFrequency getTerms() throws IOException {
184: return searchService.getTerms(h.id(index));
185: }
186:
187: public void toXMLString(StringBuffer sb) {
188: sb.append("<result"); //$NON-NLS-1$
189: sb.append(" index=\"").append(getIndex()).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
190: sb.append(" score=\"").append(getScore()).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
191: sb
192: .append(" sid=\"").append(StringUtils.xmlEscape(getId())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
193: sb
194: .append(" reference=\"").append(StringUtils.xmlEscape(getReference())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
195: try {
196: sb.append(" title=\"").append( //$NON-NLS-1$
197: new String(Base64.encodeBase64(getTitle().getBytes(
198: "UTF-8")), "UTF-8")).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
199: } catch (UnsupportedEncodingException e) {
200: sb
201: .append(" title=\"").append(StringUtils.xmlEscape(getTitle())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
202: }
203: sb
204: .append(" tool=\"").append(StringUtils.xmlEscape(getTool())).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
205: sb
206: .append(" url=\"").append(StringUtils.xmlEscape(getUrl())).append("\" />"); //$NON-NLS-1$ //$NON-NLS-2$
207: }
208:
209: }
|