/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/component/service/impl/SearchResultResponseImpl.java $ * $Id: SearchResultResponseImpl.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.Map; 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.search.Query; 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.TermFrequency; import org.sakaiproject.search.component.Messages; import org.xml.sax.Attributes; /** * @author ieb */ public class SearchResultResponseImpl implements SearchResult { private static Log log = LogFactory.getLog(SearchResultResponseImpl.class); String[] fieldNames = null; private Query query = null; private Analyzer analyzer = null; private String url; private SearchIndexBuilder searchIndexBuilder; private Map<String, String> attributes; public SearchResultResponseImpl(Map<String, String> attributes, Query query, Analyzer analyzer, SearchIndexBuilder searchIndexBuilder, SearchService searchService) throws IOException { this.attributes = attributes; this.query = query; this.analyzer = analyzer; this.searchIndexBuilder = searchIndexBuilder; } public SearchResultResponseImpl(Attributes atts, Query query, Analyzer analyzer, SearchIndexBuilder searchIndexBuilder, SearchService searchService) throws IOException { Map<String, String> m = new HashMap<String, String>(); for ( int i = 0; i < atts.getLength(); i++ ) { m.put(atts.getLocalName(i),atts.getValue(i)); } try { String title = (String)m.get("title"); //$NON-NLS-1$ if ( title != null ) { m.put("title", new String(Base64.decodeBase64(title.getBytes("UTF-8")),"UTF-8")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } catch (UnsupportedEncodingException e) { log.debug(e); } this.attributes = m; this.query = query; this.analyzer = analyzer; this.searchIndexBuilder = searchIndexBuilder; } public float getScore() { return Float.parseFloat((String)attributes.get("score")); //$NON-NLS-1$ } public String getId() { return (String)attributes.get("sid"); //$NON-NLS-1$ } public String[] getFieldNames() { if (fieldNames != null) { return fieldNames; } fieldNames = new String[attributes.size()]; int ii = 0; for (Iterator<String> i = attributes.keySet().iterator(); i.hasNext();) { fieldNames[ii++] = (String) i.next(); } return fieldNames; } public String[] getValues(String fieldName) { return new String[] {(String)attributes.get(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], new String[] { (String) attributes .get(fieldNames[i]) }); } return hm; } public String getUrl() { if (url == null) url = (String) attributes.get("url"); //$NON-NLS-1$ return url; } public String getTitle() { // I Have a feeling that this is not required as its already HTML Encoded return (String) attributes .get("title"); //$NON-NLS-1$ } public String getTool() { // I Have a feeling that this is not required as its already HTML encoded return (String) attributes .get("tool"); //$NON-NLS-1$ } public int getIndex() { return Integer.parseInt((String)attributes.get("index")); //$NON-NLS-1$ } 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 EntityContentProducer sep = searchIndexBuilder .newEntityContentProducer(getReference()); if (sep != null) { sb.append(sep.getContent(getReference())); } 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("SearchResultResponseImpl.11") + e.getMessage(); //$NON-NLS-1$ } catch (InvalidTokenOffsetsException e) { return Messages.getString("SearchResultResponseImpl.11") + e.getMessage(); } } public String getReference() { return (String) attributes.get("reference"); //$NON-NLS-1$ } public TermFrequency getTerms() throws IOException { return null; } 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(" 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() { return (String) attributes.get("site"); } public boolean isCensored() { return false; } public void setUrl(String newUrl) { url = newUrl; } public boolean hasPortalUrl() { log.info("hasPortalUrl(" + getReference()); EntityContentProducer sep = searchIndexBuilder .newEntityContentProducer(getReference()); if (sep != null) { log.info("got ECP for " + getReference()); if (PortalUrlEnabledProducer.class.isAssignableFrom(sep.getClass())) { log.info("has portalURL!"); return true; } } return false; } }