/**
* Bobo Browse Engine - High performance faceted/parametric search implementation
* that handles various types of semi-structured data. Written in Java.
*
* Copyright (C) 2005-2006 John Wang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* To contact the project administrators for the bobo-browse project,
* please go to https://sourceforge.net/projects/bobo-browse/, or
* send mail to owner@browseengine.com.
*/
package com.browseengine.bobo.servlet;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.regex.Pattern;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
import org.json.JSONException;
import com.browseengine.bobo.api.BrowseException;
import com.browseengine.bobo.api.BrowseRequest;
import com.browseengine.bobo.api.BrowseResult;
import com.browseengine.bobo.impl.QueryProducer;
import com.browseengine.bobo.protobuf.BrowseProtobufConverter;
import com.browseengine.bobo.server.protocol.BoboHttpRequestParam;
import com.browseengine.bobo.server.protocol.BrowseJSONSerializer;
import com.browseengine.bobo.service.BrowseService;
import com.browseengine.bobo.service.BrowseServiceFactory;
import com.browseengine.bobo.service.util.XStreamDispenser;
import com.browseengine.solr.BoboRequestBuilder;
import com.thoughtworks.xstream.XStream;
public class BrowseServlet
extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
private static Logger logger=Logger.getLogger(BrowseServlet.class);
private static class BoboDefaultQueryBuilder{
BoboDefaultQueryBuilder(){
}
public Query parseQuery(String query, String defaultField) {
try {
return QueryProducer.convert(query,defaultField);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
private static Pattern sortSep = Pattern.compile(",");
public Sort parseSort(String sortSpec) {
if (sortSpec==null || sortSpec.length()==0) return null;
String[] parts = sortSep.split(sortSpec.trim());
if (parts.length == 0) return null;
SortField[] lst = new SortField[parts.length];
for( int i=0; i<parts.length; i++ ) {
String part = parts[i].trim();
boolean top=true;
int idx = part.indexOf( ' ' );
if( idx > 0 ) {
String order = part.substring( idx+1 ).trim();
if( "desc".equals( order ) || "top".equals(order) ) {
top = true;
}
else if ("asc".equals(order) || "bottom".equals(order)) {
top = false;
}
else {
throw new IllegalArgumentException("Unknown sort order: "+order);
}
part = part.substring( 0, idx ).trim();
}
else {
throw new IllegalArgumentException("Missing sort order." );
}
if( "score".equals(part) ) {
if (top) {
// If thre is only one thing in the list, just do the regular thing...
if( parts.length == 1 ) {
return null; // do normal scoring...
}
lst[i] = SortField.FIELD_SCORE;
}
else {
lst[i] = new SortField(null, SortField.SCORE, true);
}
}
else {
lst[i] = new SortField(part,SortField.STRING,top);
}
}
return new Sort(lst);
}
}
private BrowseService _svc;
public BrowseServlet() {
super();
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
_svc=getServiceInstance(config);
}
protected BrowseService getServiceInstance(ServletConfig config) throws ServletException{
String indexDir=System.getProperty("index.directory");
if (indexDir==null || indexDir.length()==0){
indexDir = getInitParameter("index.directory");
}
if (null == indexDir || indexDir.length() == 0)
throw new ServletException("No index directory configured");
try {
return BrowseServiceFactory.createBrowseService(new File(indexDir));
} catch (BrowseException e) {
throw new ServletException(e.getMessage(),e.getCause());
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
SolrParams params = new BoboHttpRequestParam(req);
String qstring = params.get(CommonParams.Q);
String df = params.get(CommonParams.DF);
String sortString = params.get(CommonParams.SORT);
BoboDefaultQueryBuilder qbuilder = new BoboDefaultQueryBuilder();
Query query = qbuilder.parseQuery(qstring, df);
Sort sort = qbuilder.parseSort(sortString);
BrowseRequest br = null;
try {
br=BoboRequestBuilder.buildRequest(params,query,sort);
logger.info("REQ: "+BrowseProtobufConverter.toProtoBufString(br));
BrowseResult result=_svc.browse(br);
res.setCharacterEncoding("UTF-8");
Writer writer=res.getWriter();
String outputFormat=req.getParameter("output");
if ("json".equals(outputFormat)){
try{
String val=BrowseJSONSerializer.serialize(result);
writer.write(val);
}
catch(JSONException je){
throw new IOException(je.getMessage());
}
}
else{
XStream xstream=XStreamDispenser.getXMLXStream();
writer.write(xstream.toXML(result));
}
} catch (BrowseException e) {
throw new ServletException(e.getMessage(),e);
}
}
@Override
public void destroy() {
super.destroy();
try {
_svc.close();
} catch (BrowseException e) {
logger.warn("Problem shutting down browse engine.",e);
}
}
}