package org.fastcatsearch.http.action.service;
import org.fastcatsearch.control.JobService;
import org.fastcatsearch.control.ResultFuture;
import org.fastcatsearch.error.SearchError;
import org.fastcatsearch.http.action.ActionRequest;
import org.fastcatsearch.http.action.ActionResponse;
import org.fastcatsearch.http.action.ServiceAction;
import org.fastcatsearch.http.writer.AbstractSearchResultWriter;
import org.fastcatsearch.http.writer.SearchResultWriter;
import org.fastcatsearch.ir.query.Metadata;
import org.fastcatsearch.ir.query.Query;
import org.fastcatsearch.job.Job;
import org.fastcatsearch.query.QueryMap;
import org.fastcatsearch.util.ResponseWriter;
import org.fastcatsearch.util.ResultWriterException;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Writer;
import java.util.concurrent.atomic.AtomicLong;
public abstract class AbstractSearchAction extends ServiceAction {
private static final Logger requestLogger = LoggerFactory.getLogger("REQUEST_LOG");
private static final Logger searchErrorLogger = LoggerFactory.getLogger("SEARCH_ERROR_LOG");
private static AtomicLong taskSeq = new AtomicLong();
public static final int DEFAULT_TIMEOUT = 5; // 5초.
protected abstract Job createSearchJob(QueryMap queryMap);
protected AbstractSearchResultWriter createSearchResultWriter(Writer writer, boolean isFieldLowercase, boolean noUnicode) {
return new SearchResultWriter(getSearchResultWriter(writer, isFieldLowercase, noUnicode));
}
public Object doSearch(long requestId, QueryMap queryMap, int timeout, Writer writer) throws Exception {
long searchTime = 0;
long st = System.nanoTime();
Job searchJob = createSearchJob(queryMap);
ResultFuture jobResult = JobService.getInstance().offer(searchJob);
Object obj = jobResult.poll(timeout);
searchTime = (System.nanoTime() - st) / 1000000;
// searchOption에서 lowercase가 존재하는지 확인후, 존재하면 lowercase로 결과를 기록하도록 한다.
String so = queryMap.get(Query.EL.so.name());
Metadata meta = new Metadata();
meta.setSearchOptions(so);
boolean isFieldLowercase = meta.isSearchOption(Query.SEARCH_OPT_LOWERCASE);
boolean noUnicode = meta.isSearchOption(Query.SEARCH_OPT_NOUNICODE);
AbstractSearchResultWriter resultWriter = createSearchResultWriter(writer, isFieldLowercase, noUnicode);
try {
resultWriter.writeResult(obj, searchTime, jobResult.isSuccess());
} catch (ResultWriterException e) {
logger.error("", e);
}
writer.close();
return obj;
}
protected long getRequestId() {
return taskSeq.getAndIncrement();
}
@Override
public void doAction(ActionRequest request, ActionResponse response) throws Exception {
long requestId = getRequestId();
requestLogger.info("request id:{} uri:{} param:{}", requestId, request.uri(), request.getParameterString());
logger.debug("request.getParameterMap() >> {}", request.getParameterMap());
QueryMap queryMap = new QueryMap(request.getParameterMap());
logger.debug("queryMap tostring>> {}", queryMap);
Integer timeout = request.getIntParameter("timeout", DEFAULT_TIMEOUT);
String responseCharset = request.getParameter("responseCharset", DEFAULT_CHARSET);
writeHeader(response, responseCharset);
logger.debug("queryMap = {}", queryMap);
logger.debug("timeout = {} s", timeout);
if (timeout == null) {
timeout = DEFAULT_TIMEOUT;
}
Writer writer = response.getWriter();
response.setStatus(HttpResponseStatus.OK);
Object obj = null;
try {
obj = doSearch(requestId, queryMap, timeout, writer);
} finally {
writer.close();
requestLogger.info("end request id:{}",requestId);
}
if(obj instanceof Exception) {
Exception e = (Exception) obj;
searchErrorLogger.error("REQ-{} URL: {}?{}", requestId, request.uri(), request.getParameterString());
if(e instanceof SearchError) {
searchErrorLogger.error("RES-{} : {}", requestId, e.getMessage());
} else {
searchErrorLogger.error("RES-" + requestId, e);
}
}
}
protected ResponseWriter getSearchResultWriter(Writer writer, boolean isFieldLowercase, boolean noUnicode) {
return getSearchResultWriter(writer, "_search_callback", isFieldLowercase, noUnicode);
}
protected ResponseWriter getSearchResultWriter(Writer writer, String jsonCallback, boolean isFieldLowercase, boolean noUnicode) {
return getResponseWriter(writer, ServiceAction.DEFAULT_ROOT_ELEMENT, true, jsonCallback, isFieldLowercase, noUnicode);
}
}