這段源碼特別重要,如果想在solr應用之上開發自己的代碼,這段源碼很值得研究。
HttpSolrCall
package org.apache.solr.servlet;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.InputStreamEntity;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.Aliases;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Replica.State;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CollectionParams.CollectionAction;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrConfig.HttpCachingConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.ContentStreamHandlerBase;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryRequestBase;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.QueryResponseWriterUtil;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.security.AuthenticationPlugin;
import org.apache.solr.security.AuthorizationContext;
import org.apache.solr.security.AuthorizationContext.CollectionRequest;
import org.apache.solr.security.AuthorizationContext.RequestType;
import org.apache.solr.security.AuthorizationPlugin;
import org.apache.solr.security.AuthorizationResponse;
import org.apache.solr.security.PKIAuthenticationPlugin;
import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
import org.apache.solr.servlet.cache.Method;
import org.apache.solr.util.RTimerTree;
import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpSolrCall
{
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
static final Random random;
protected final SolrDispatchFilter solrDispatchFilter;
protected final CoreContainer cores;
protected final HttpServletRequest req;
protected final HttpServletResponse response;
protected final boolean retry;
protected SolrCore core = null;
protected SolrQueryRequest solrReq = null;
protected SolrRequestHandler handler = null;
protected final SolrParams queryParams;
protected String path;
protected SolrDispatchFilter.Action action;
protected String coreUrl;
protected SolrConfig config;
protected Map<String, Integer> invalidStates;
protected AuthorizationContext.RequestType requestType;
protected List<String> collectionsList;
static final String CONNECTION_HEADER = "Connection";
static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
static final String CONTENT_LENGTH_HEADER = "Content-Length";
public AuthorizationContext.RequestType getRequestType()
{
return this.requestType;
}
public List<String> getCollectionsList()
{
return this.collectionsList;
}
public HttpSolrCall(SolrDispatchFilter solrDispatchFilter, CoreContainer cores, HttpServletRequest request, HttpServletResponse response, boolean retry)
{
this.solrDispatchFilter = solrDispatchFilter;
this.cores = cores;
this.req = request;
this.response = response;
this.retry = retry;
this.requestType = AuthorizationContext.RequestType.UNKNOWN;
//獲取查詢參數
this.queryParams = SolrRequestParsers.parseQueryString(this.req.getQueryString());
}
public String getPath() {
return this.path;
}
public HttpServletRequest getReq()
{
return this.req;
}
public SolrCore getCore() {
return this.core;
}
public SolrParams getQueryParams() {
return this.queryParams;
}
private void init() throws Exception
{
Aliases aliases = null;
String corename = "";
String origCorename = null;
this.req.setAttribute("org.apache.solr.RequestTimer", new RTimerTree());
//將coreContainer放入web容器,放入之後當前請求整個web容器共享
//那麼延伸來講,當前請求的web組件共享這個容器,例如在某個servlet中
//我們可以通過CoreContainer coreContainer=(CoreContainer)customerServletRequest.getAttribute("org.apache.solr.CoreContainer");
this.req.setAttribute("org.apache.solr.CoreContainer", this.cores);
//獲取請求的servlet路徑
//例如:http://localhost:8080/solr/my_solr/select?q=*%3A*&wt=json&indent=true&qt=queryrefine
//路徑爲:my_solr/select
this.path = this.req.getServletPath();
if (this.req.getPathInfo() != null)
{
this.path = new StringBuilder().append(this.path).append(this.req.getPathInfo()).toString();
}
String alternate = this.cores.getManagementPath();
if ((alternate != null) && (this.path.startsWith(alternate))) {
this.path = this.path.substring(0, alternate.length());
}
int idx = this.path.indexOf(58);
if (idx > 0)
{
this.path = this.path.substring(0, idx);
}
boolean usingAliases = false;
//通過請求的servlet獲取對於的handler處理器
//例如:http://localhost:8080/solr/my_solr/select?q=*%3A*&wt=json&indent=true&qt=queryrefine
//通過"select"獲取對應handler
//對應我們看到solrconfig.xml中的配置
//<requestHandler name="/select" class="solr.SearchHandler">
//實際開發過程中:this.handler = this.cores.getRequestHandler("/coustomerHandler");
//對應solrconfig.xml中的配置
//<requestHandler name="/coustomerHandler" class="com.upxiaofeng.solr.coustomerHandler">
this.handler = this.cores.getRequestHandler(this.path);
if (this.handler != null) {
this.solrReq = SolrRequestParsers.DEFAULT.parse(null, this.path, this.req);
this.solrReq.getContext().put(CoreContainer.class.getName(), this.cores);
this.requestType = AuthorizationContext.RequestType.ADMIN;
this.action = SolrDispatchFilter.Action.ADMIN;
return;
}
idx = this.path.indexOf("/", 1);
if (idx > 1)
{
corename = this.path.substring(1, idx);
if (this.cores.isZooKeeperAware()) {
origCorename = corename;
ZkStateReader reader = this.cores.getZkController().getZkStateReader();
aliases = reader.getAliases();
if ((aliases != null) && (aliases.collectionAliasSize() > 0)) {
usingAliases = true;
String alias = aliases.getCollectionAlias(corename);
if (alias != null) {
this.collectionsList = StrUtils.splitSmart(alias, ",", true);
corename = (String)this.collectionsList.get(0);
}
}
}
//通過corename獲取對應的solr core,例如我們叫my_solr
//實際上就是我們core.properties配置的name屬性
//實際開發中就是通過獲取我們想要的core
//CoreContainer coreContainer=(CoreContainer)HttpServletRequest.getAttribute("org.apache.solr.CoreContainer");
//Solrcore core = coreContainer.getCore("my_solr");
this.core = this.cores.getCore(corename);
if (this.core != null) {
this.path = this.path.substring(idx); } else {
if (this.cores.isCoreLoading(corename)) {
throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, "SolrCore is loading");
}
this.core = this.cores.getCore(corename);
if (this.core != null) {
this.path = this.path.substring(idx);
}
}
}
if ((this.core == null) &&
(!this.cores.isZooKeeperAware())) {
this.core = this.cores.getCore("");
}
if ((this.core == null) && (this.cores.isZooKeeperAware()))
{
this.core = getCoreByCollection(corename);
if (this.core != null)
{
this.path = this.path.substring(idx);
if (this.collectionsList == null)
this.collectionsList = new ArrayList();
this.collectionsList.add(corename);
}
extractRemotePath(corename, origCorename, idx);
if (this.action != null) return;
}
//使用solr core實例
if (this.core != null) {
MDCLoggingContext.setCore(this.core);
//獲取SolrConfig對象
this.config = this.core.getSolrConfig();
//獲取SolrRequestParsers解析對象
SolrRequestParsers parser = this.config.getRequestParsers();
//獲取對應handler
extractHandlerFromURLPath(parser);
if (this.action != null) return;
if (this.handler != null)
{
if (this.solrReq == null) {
//得到查詢請求對象
//實際開發中可以根據自己的需求來處理獲取對應的查詢對象
//如:this.solrReq = parser.parse(this.core, "select", this.req);
this.solrReq = parser.parse(this.core, this.path, this.req);
}
if (usingAliases) {
processAliases(aliases, this.collectionsList);
}
this.action = SolrDispatchFilter.Action.PROCESS;
return;
}
}
log.debug(new StringBuilder().append("no handler or core retrieved for ").append(this.path).append(", follow through...").toString());
this.action = SolrDispatchFilter.Action.PASSTHROUGH;
}
/**
* 獲取對應handler處理器
* @param parser
* @throws Exception
*/
private void extractHandlerFromURLPath(SolrRequestParsers parser)
throws Exception
{
if ((this.handler == null) && (this.path.length() > 1)) {
this.handler = this.core.getRequestHandler(this.path);
if (this.handler == null)
{
if ((this.path.equals("/schema")) || (this.path.startsWith("/schema/"))) {
this.solrReq = parser.parse(this.core, this.path, this.req);
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(this.solrReq, new SolrQueryResponse()));
if (this.path.equals(this.req.getServletPath()))
{
this.action = SolrDispatchFilter.Action.PASSTHROUGH;
return;
}
this.action = SolrDispatchFilter.Action.FORWARD;
return;
}
}
//沒有處理器但是允許處理查詢
if ((this.handler == null) && (parser.isHandleSelect()) && (
("/select".equals(this.path)) || ("/select/".equals(this.path)))) {
this.solrReq = parser.parse(this.core, this.path, this.req);
this.invalidStates = checkStateIsValid(this.solrReq.getParams().get("_stateVer_"));
//通過url中傳入的qt參數得到查詢對應的handler
String qt = this.solrReq.getParams().get("qt");
this.handler = this.core.getRequestHandler(qt);
if (this.handler == null) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, new StringBuilder().append("unknown handler: ").append(qt).toString());
}
if ((qt != null) && (qt.startsWith("/")) && ((this.handler instanceof ContentStreamHandlerBase)))
{
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, new StringBuilder().append("Invalid Request Handler ('qt'). Do not use /select to access: ").append(qt).toString());
}
}
}
}
private void extractRemotePath(String corename, String origCorename, int idx) throws UnsupportedEncodingException, KeeperException, InterruptedException
{
if ((this.core == null) && (idx > 0)) {
this.coreUrl = getRemotCoreUrl(corename, origCorename);
this.invalidStates = checkStateIsValid(this.queryParams.get("_stateVer_"));
if (this.coreUrl != null)
{
if (this.queryParams
.get("update.distrib") == null)
{
this.path = this.path.substring(idx);
if (this.invalidStates != null)
{
throw new SolrException(SolrException.ErrorCode.INVALID_STATE, new String(Utils.toJSON(this.invalidStates), org.apache.lucene.util.IOUtils.UTF_8));
}
this.action = SolrDispatchFilter.Action.REMOTEQUERY; return;
}
}
if (!this.retry)
{
ZkStateReader reader = this.cores.getZkController()
.getZkStateReader();
reader.updateAliases();
this.action = SolrDispatchFilter.Action.RETRY;
}
}
}
public SolrDispatchFilter.Action call()
throws IOException
{
MDCLoggingContext.reset();
MDCLoggingContext.setNode(this.cores);
if (this.cores == null) {
sendError(503, "Server is shutting down or failed to initialize");
return SolrDispatchFilter.Action.RETURN;
}
if (this.solrDispatchFilter.abortErrorMessage != null) {
sendError(500, this.solrDispatchFilter.abortErrorMessage);
return SolrDispatchFilter.Action.RETURN;
}
try
{
init();
AuthorizationResponse authResponse;
if ((this.cores.getAuthorizationPlugin() != null) && (shouldAuthorize())) {
AuthorizationContext context = getAuthCtx();
log.debug("AuthorizationContext : {}", context);
authResponse = this.cores.getAuthorizationPlugin().authorize(context);
Map headers;
if (authResponse.statusCode == AuthorizationResponse.PROMPT.statusCode) {
headers = (Map)getReq().getAttribute(AuthenticationPlugin.class.getName());
if (headers != null)
{
Map.Entry e;
for (Iterator localIterator1 = headers.entrySet().iterator(); localIterator1.hasNext(); this.response.setHeader((String)e.getKey(), (String)e.getValue())) e = (Map.Entry)localIterator1.next();
}
log.debug(new StringBuilder().append("USER_REQUIRED ").append(this.req.getHeader("Authorization")).append(" ").append(this.req.getUserPrincipal()).toString());
}
if ((authResponse.statusCode != 202) && (authResponse.statusCode != 200)) {
log.info("USER_REQUIRED auth header {} context : {} ", this.req.getHeader("Authorization"), context);
sendError(authResponse.statusCode, new StringBuilder().append("Unauthorized request, Response code: ").append(authResponse.statusCode).toString());
return SolrDispatchFilter.Action.RETURN;
}
}
HttpServletResponse resp = this.response;
switch (3.$SwitchMap$org$apache$solr$servlet$SolrDispatchFilter$Action[this.action.ordinal()]) {
case 1:
handleAdminRequest();
return SolrDispatchFilter.Action.RETURN;
case 2:
remoteQuery(new StringBuilder().append(this.coreUrl).append(this.path).toString(), resp);
return SolrDispatchFilter.Action.RETURN;
case 3:
//做對應的http緩存
Method reqMethod = Method.getMethod(this.req.getMethod());
HttpCacheHeaderUtil.setCacheControlHeader(this.config, resp, reqMethod);
//如果沒有緩存,即狀態不爲304
if ((this.config.getHttpCachingConfig().isNever304()) ||
(!HttpCacheHeaderUtil.doCacheHeaderValidation(this.solrReq, this.req, reqMethod, resp)))
{
//實例化SolrQueryResponse
solrRsp = new SolrQueryResponse();
//設置參數
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(this.solrReq, solrRsp));
//執行查詢
execute(solrRsp);
HttpCacheHeaderUtil.checkHttpCachingVeto(solrRsp, resp, reqMethod);
Iterator headers = solrRsp.httpHeaders();
while (headers.hasNext()) {
Map.Entry entry = (Map.Entry)headers.next();
resp.addHeader((String)entry.getKey(), (String)entry.getValue());
}
//獲取當前請求響應的writer
//這個方法有重載
//public final QueryResponseWriter getQueryResponseWriter(String writerName)
//實際開發過程中,可以自己去實現自己的writer。對應solrconfig.xml中的配置
//<queryResponseWriter name="upxiaofeng" class="com.upxiaofeng.solr.VanclResponseWriter">
//<str name="content-type">text/plain; charset=UTF-8</str>
//</queryResponseWriter>
//如:QueryResponseWriter responseWriter = this.core.getQueryResponseWriter("upxiaofeng");
//public final QueryResponseWriter getQueryResponseWriter(SolrQueryRequest request)
QueryResponseWriter responseWriter = this.core.getQueryResponseWriter(this.solrReq);
if (this.invalidStates != null) this.solrReq.getContext().put("_stateVer_", this.invalidStates);
writeResponse(solrRsp, responseWriter, reqMethod);
}
return SolrDispatchFilter.Action.RETURN;
}return this.action;
}
catch (Throwable ex)
{
SolrQueryResponse solrRsp;
sendError(ex);
Throwable t = ex;
while (t != null) {
if ((t instanceof Error)) {
if (t != ex) {
log.error("An Error was wrapped in another exception - please report complete stacktrace on SOLR-6161", ex);
}
throw ((Error)t);
}
t = t.getCause();
}
return SolrDispatchFilter.Action.RETURN;
} finally {
MDCLoggingContext.clear();
}
}
private boolean shouldAuthorize()
{
if ("/admin/info/key".equals(this.path)) return false;
if ((this.cores.getPkiAuthenticationPlugin() != null) && (this.req.getUserPrincipal() != null)) {
boolean b = this.cores.getPkiAuthenticationPlugin().needsAuthorization(this.req);
log.debug("PkiAuthenticationPlugin says authorization required : {} ", Boolean.valueOf(b));
return b;
}
return true;
}
void destroy() {
try {
if (this.solrReq != null) {
log.debug("Closing out SolrRequest: {}", this.solrReq);
this.solrReq.close();
}
AuthenticationPlugin authcPlugin;
try {
if (this.core != null) this.core.close();
SolrRequestInfo.clearRequestInfo(); } finally { SolrRequestInfo.clearRequestInfo(); }
if (authcPlugin != null) authcPlugin.closeRequest();
}
finally
{
AuthenticationPlugin authcPlugin;
try
{
if (this.core != null) this.core.close();
SolrRequestInfo.clearRequestInfo(); } finally { SolrRequestInfo.clearRequestInfo(); }
if (authcPlugin != null) authcPlugin.closeRequest();
}
}
private void remoteQuery(String coreUrl, HttpServletResponse resp) throws IOException {
HttpRequestBase method = null;
HttpEntity httpEntity = null;
try {
String urlstr = new StringBuilder().append(coreUrl).append(this.queryParams.toQueryString()).toString();
boolean isPostOrPutRequest = ("POST".equals(this.req.getMethod())) || ("PUT".equals(this.req.getMethod()));
if ("GET".equals(this.req.getMethod())) {
method = new HttpGet(urlstr);
} else if ("HEAD".equals(this.req.getMethod())) {
method = new HttpHead(urlstr);
} else if (isPostOrPutRequest)
{
HttpEntityEnclosingRequestBase entityRequest = "POST"
.equals(this.req
.getMethod()) ? new HttpPost(urlstr) : new HttpPut(urlstr);
HttpEntity entity = new InputStreamEntity(this.req.getInputStream(), this.req.getContentLength());
entityRequest.setEntity(entity);
method = entityRequest;
} else if ("DELETE".equals(this.req.getMethod())) {
method = new HttpDelete(urlstr);
}
else {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, new StringBuilder().append("Unexpected method type: ")
.append(this.req
.getMethod()).toString());
}
for (Enumeration e = this.req.getHeaderNames(); e.hasMoreElements(); ) {
String headerName = (String)e.nextElement();
if ((!"host".equalsIgnoreCase(headerName)) &&
(!"authorization"
.equalsIgnoreCase(headerName)) &&
(!"accept"
.equalsIgnoreCase(headerName)))
{
method.addHeader(headerName, this.req.getHeader(headerName));
}
}
if ((method instanceof HttpEntityEnclosingRequest)) {
method.removeHeaders("Transfer-Encoding");
method.removeHeaders("Content-Length");
}
HttpResponse response = this.solrDispatchFilter.httpClient.execute(method);
int httpStatus = response.getStatusLine().getStatusCode();
httpEntity = response.getEntity();
resp.setStatus(httpStatus);
for (HeaderIterator responseHeaders = response.headerIterator(); responseHeaders.hasNext(); ) {
Header header = responseHeaders.nextHeader();
if ((header != null) && (!header.getName().equalsIgnoreCase("Transfer-Encoding")) &&
(!header
.getName().equalsIgnoreCase("Connection"))) {
resp.addHeader(header.getName(), header.getValue());
}
}
if (httpEntity != null) {
if (httpEntity.getContentEncoding() != null)
resp.setCharacterEncoding(httpEntity.getContentEncoding().getValue());
if (httpEntity.getContentType() != null) resp.setContentType(httpEntity.getContentType().getValue());
InputStream is = httpEntity.getContent();
OutputStream os = resp.getOutputStream();
org.apache.commons.io.IOUtils.copyLarge(is, os);
}
}
catch (IOException e) {
sendError(new SolrException(SolrException.ErrorCode.SERVER_ERROR, new StringBuilder().append("Error trying to proxy request for url: ").append(coreUrl).toString(), e));
}
finally
{
Utils.consumeFully(httpEntity);
}
}
protected void sendError(Throwable ex) throws IOException
{
Exception exp = null;
SolrCore localCore = null;
try {
SolrQueryResponse solrResp = new SolrQueryResponse();
if ((ex instanceof Exception))
solrResp.setException((Exception)ex);
else {
solrResp.setException(new RuntimeException(ex));
}
localCore = this.core;
if (this.solrReq == null)
{
SolrParams solrParams;
SolrParams solrParams;
if (this.req != null)
{
solrParams = SolrRequestParsers.parseQueryString(this.req.getQueryString());
}
else {
solrParams = new MapSolrParams(Collections.emptyMap());
}
this.solrReq = new SolrQueryRequestBase(this.core, solrParams) {
};
}
QueryResponseWriter writer = this.core.getQueryResponseWriter(this.solrReq);
writeResponse(solrResp, writer, Method.GET);
}
catch (Exception e)
{
SimpleOrderedMap info;
int code;
exp = e;
}
finally
{
try
{
SimpleOrderedMap info;
int code;
if (exp != null) {
SimpleOrderedMap info = new SimpleOrderedMap();
int code = ResponseUtils.getErrorInfo(ex, info, log);
sendError(code, info.toString());
}
} finally {
if ((this.core == null) && (localCore != null))
localCore.close();
}
}
}
protected void sendError(int code, String message) throws IOException
{
try {
this.response.sendError(code, message);
} catch (EOFException e) {
log.info("Unable to write error response, client closed connection or we are shutting down", e);
}
}
/**
* 執行查詢
* @param rsp
*/
protected void execute(SolrQueryResponse rsp)
{
this.solrReq.getContext().put("webapp", this.req.getContextPath());
this.solrReq.getCore().execute(this.handler, this.solrReq, rsp);
}
private void handleAdminRequest() throws IOException {
SolrQueryResponse solrResp = new SolrQueryResponse();
SolrCore.preDecorateResponse(this.solrReq, solrResp);
this.handler.handleRequest(this.solrReq, solrResp);
SolrCore.postDecorateResponse(this.handler, this.solrReq, solrResp);
if ((log.isInfoEnabled()) && (solrResp.getToLog().size() > 0)) {
log.info(solrResp.getToLogAsString("[admin]"));
}
QueryResponseWriter respWriter = (QueryResponseWriter)SolrCore.DEFAULT_RESPONSE_WRITERS.get(this.solrReq.getParams().get("wt"));
if (respWriter == null) respWriter = (QueryResponseWriter)SolrCore.DEFAULT_RESPONSE_WRITERS.get("standard");
writeResponse(solrResp, respWriter, Method.getMethod(this.req.getMethod()));
}
private void processAliases(Aliases aliases, List<String> collectionsList)
{
String collection = this.solrReq.getParams().get("collection");
if (collection != null) {
collectionsList = StrUtils.splitSmart(collection, ",", true);
}
if (collectionsList != null)
{
Set newCollectionsList = new HashSet(collectionsList
.size());
for (String col : collectionsList) {
String al = aliases.getCollectionAlias(col);
if (al != null) {
List aliasList = StrUtils.splitSmart(al, ",", true);
newCollectionsList.addAll(aliasList);
} else {
newCollectionsList.add(col);
}
}
if (newCollectionsList.size() > 0) {
StringBuilder collectionString = new StringBuilder();
Iterator it = newCollectionsList.iterator();
int sz = newCollectionsList.size();
for (int i = 0; i < sz; i++) {
collectionString.append((String)it.next());
if (i < newCollectionsList.size() - 1) {
collectionString.append(",");
}
}
ModifiableSolrParams params = new ModifiableSolrParams(this.solrReq
.getParams());
params.set("collection", new String[] { collectionString.toString() });
this.solrReq.setParams(params);
}
}
}
/**
* 響應請求
* @param solrRsp
* @param responseWriter
* @param reqMethod
* @throws IOException
*/
private void writeResponse(SolrQueryResponse solrRsp, QueryResponseWriter responseWriter, Method reqMethod) throws IOException
{
try {
Object invalidStates = this.solrReq.getContext().get("_stateVer_");
if (invalidStates != null) solrRsp.add("_stateVer_", invalidStates);
String ct = responseWriter.getContentType(this.solrReq, solrRsp);
if (null != ct) this.response.setContentType(ct);
if (solrRsp.getException() != null) {
NamedList info = new SimpleOrderedMap();
int code = ResponseUtils.getErrorInfo(solrRsp.getException(), info, log);
solrRsp.add("error", info);
this.response.setStatus(code);
}
if (Method.HEAD != reqMethod)
//QueryResponseWriterUtil進一步處理響應 QueryResponseWriterUtil.writeQueryResponse(this.response.getOutputStream(), responseWriter, this.solrReq, solrRsp, ct);
}
catch (EOFException e)
{
log.info("Unable to write response, client closed connection or we are shutting down", e);
}
}
private Map<String, Integer> checkStateIsValid(String stateVer) {
Map result = null;
if ((stateVer != null) && (!stateVer.isEmpty()) && (this.cores.isZooKeeperAware()))
{
String[] pairs = StringUtils.split(stateVer, '|');
for (String pair : pairs) {
String[] pcs = StringUtils.split(pair, ':');
if ((pcs.length == 2) && (!pcs[0].isEmpty()) && (!pcs[1].isEmpty())) {
Integer status = this.cores.getZkController().getZkStateReader().compareStateVersions(pcs[0], Integer.parseInt(pcs[1]));
if (status != null) {
if (result == null) result = new HashMap();
result.put(pcs[0], status);
}
}
}
}
return result;
}
private SolrCore getCoreByCollection(String collection) {
ZkStateReader zkStateReader = this.cores.getZkController().getZkStateReader();
ClusterState clusterState = zkStateReader.getClusterState();
Map slices = clusterState.getActiveSlicesMap(collection);
if (slices == null) {
return null;
}
Set liveNodes = clusterState.getLiveNodes();
Set entries = slices.entrySet();
SolrCore core = null;
for (Map.Entry entry : entries)
{
Replica leaderProps = clusterState.getLeader(collection, (String)entry.getKey());
if ((leaderProps != null) && (liveNodes.contains(leaderProps.getNodeName())) && (leaderProps.getState() == Replica.State.ACTIVE)) {
core = checkProps(leaderProps);
if (core != null) {
return core;
}
}
Map shards = ((Slice)entry.getValue()).getReplicasMap();
Set shardEntries = shards.entrySet();
for (Map.Entry shardEntry : shardEntries) {
Replica zkProps = (Replica)shardEntry.getValue();
if ((liveNodes.contains(zkProps.getNodeName())) && (zkProps.getState() == Replica.State.ACTIVE)) {
core = checkProps(zkProps);
if (core != null) {
return core;
}
}
}
}
return null;
}
private SolrCore checkProps(ZkNodeProps zkProps)
{
SolrCore core = null;
if (this.cores.getZkController().getNodeName().equals(zkProps.getStr("node_name"))) {
String corename = zkProps.getStr("core");
core = this.cores.getCore(corename);
}
return core;
}
private void getSlicesForCollections(ClusterState clusterState, Collection<Slice> slices, boolean activeSlices)
{
if (activeSlices) {
for (String collection : clusterState.getCollections()) {
Collection activeCollectionSlices = clusterState.getActiveSlices(collection);
if (activeCollectionSlices != null)
slices.addAll(activeCollectionSlices);
}
}
else
for (String collection : clusterState.getCollections()) {
Collection collectionSlices = clusterState.getSlices(collection);
if (collectionSlices != null)
slices.addAll(collectionSlices);
}
}
private String getRemotCoreUrl(String collectionName, String origCorename)
{
ClusterState clusterState = this.cores.getZkController().getClusterState();
Collection slices = clusterState.getActiveSlices(collectionName);
boolean byCoreName = false;
if (slices == null) {
slices = new ArrayList();
byCoreName = true;
getSlicesForCollections(clusterState, slices, true);
if (slices.isEmpty()) {
getSlicesForCollections(clusterState, slices, false);
}
}
if (slices.isEmpty()) {
return null;
}
if (this.collectionsList == null) {
this.collectionsList = new ArrayList();
}
this.collectionsList.add(collectionName);
String coreUrl = getCoreUrl(collectionName, origCorename, clusterState, slices, byCoreName, true);
if (coreUrl == null) {
coreUrl = getCoreUrl(collectionName, origCorename, clusterState, slices, byCoreName, false);
}
return coreUrl;
}
private String getCoreUrl(String collectionName, String origCorename, ClusterState clusterState, Collection<Slice> slices, boolean byCoreName, boolean activeReplicas)
{
Set liveNodes = clusterState.getLiveNodes();
List randomizedSlices = new ArrayList(slices.size());
randomizedSlices.addAll(slices);
Collections.shuffle(randomizedSlices, random);
for (Slice slice : randomizedSlices) {
List randomizedReplicas = new ArrayList();
randomizedReplicas.addAll(slice.getReplicas());
Collections.shuffle(randomizedReplicas, random);
for (Replica replica : randomizedReplicas)
if ((!activeReplicas) || ((liveNodes.contains(replica.getNodeName())) &&
(replica
.getState() == Replica.State.ACTIVE)))
{
if (((!byCoreName) || (collectionName.equals(replica.getStr("core")))) &&
(!replica.getStr("base_url").equals(this.cores.getZkController().getBaseUrl())))
{
String coreUrl;
String coreUrl;
if (origCorename != null) {
coreUrl = new StringBuilder().append(replica.getStr("base_url")).append("/").append(origCorename).toString();
} else {
coreUrl = replica.getCoreUrl();
if (coreUrl.endsWith("/")) {
coreUrl = coreUrl.substring(0, coreUrl.length() - 1);
}
}
return coreUrl;
}
}
}
return null;
}
private AuthorizationContext getAuthCtx()
{
final String resource = getPath();
SolrParams params = getQueryParams();
final ArrayList collectionRequests = new ArrayList();
Object localObject;
if (getCollectionsList() != null)
for (localObject = getCollectionsList().iterator(); ((Iterator)localObject).hasNext(); ) { collection = (String)((Iterator)localObject).next();
collectionRequests.add(new AuthorizationContext.CollectionRequest(collection));
}
String collection;
if (getPath().equals("/admin/collections")) {
if ((CollectionParams.CollectionAction.CREATE.isEqual(params.get("action"))) ||
(CollectionParams.CollectionAction.RELOAD
.isEqual(params
.get("action"))) ||
(CollectionParams.CollectionAction.DELETE
.isEqual(params
.get("action"))))
{
collectionRequests.add(new AuthorizationContext.CollectionRequest(params.get("name")));
} else if (params.get("collection") != null) {
collectionRequests.add(new AuthorizationContext.CollectionRequest(params.get("collection")));
}
}
if ((resource.equals("/select")) && (params.get("collection") != null)) {
collectionRequests.clear();
localObject = params.get("collection").split(","); collection = localObject.length; for (String str1 = 0; str1 < collection; str1++) { String collection = localObject[str1];
collectionRequests.add(new AuthorizationContext.CollectionRequest(collection));
}
}
if (this.requestType == AuthorizationContext.RequestType.UNKNOWN) {
if ((resource.startsWith("/select")) || (resource.startsWith("/get")))
this.requestType = AuthorizationContext.RequestType.READ;
if (resource.startsWith("/update")) {
this.requestType = AuthorizationContext.RequestType.WRITE;
}
}
if ((getCore() != null) && ((getCollectionsList() == null) || (getCollectionsList().size() == 0))) {
collectionRequests.add(new AuthorizationContext.CollectionRequest(getCore().getCoreDescriptor().getCollectionName()));
}
if (getQueryParams().get("collection") != null) {
collectionRequests.add(new AuthorizationContext.CollectionRequest(getQueryParams().get("collection")));
}
return new AuthorizationContext()
{
public SolrParams getParams() {
return HttpSolrCall.this.solrReq.getParams();
}
public Principal getUserPrincipal()
{
return HttpSolrCall.this.getReq().getUserPrincipal();
}
public String getHttpHeader(String s)
{
return HttpSolrCall.this.getReq().getHeader(s);
}
public Enumeration getHeaderNames()
{
return HttpSolrCall.this.getReq().getHeaderNames();
}
public List<AuthorizationContext.CollectionRequest> getCollectionRequests()
{
return collectionRequests;
}
public AuthorizationContext.RequestType getRequestType()
{
return HttpSolrCall.this.requestType;
}
public String getResource() {
return HttpSolrCall.this.path;
}
public String getHttpMethod()
{
return HttpSolrCall.this.getReq().getMethod();
}
public String toString()
{
StringBuilder response = new StringBuilder("userPrincipal: [").append(getUserPrincipal()).append("]")
.append(" type: [")
.append(HttpSolrCall.this.requestType.toString()).append("], collections: [");
for (AuthorizationContext.CollectionRequest collectionRequest : collectionRequests) {
response.append(collectionRequest.collectionName).append(", ");
}
if (collectionRequests.size() > 0) {
response.delete(response.length() - 1, response.length());
}
response.append("], Path: [").append(resource).append("]");
response.append(" path : ").append(HttpSolrCall.this.path).append(" params :").append(HttpSolrCall.this.solrReq.getParams());
return response.toString();
}
public String getRemoteAddr()
{
return HttpSolrCall.this.getReq().getRemoteAddr();
}
public String getRemoteHost()
{
return HttpSolrCall.this.getReq().getRemoteHost();
}
};
}
static
{
String seed = System.getProperty("tests.seed");
if (seed == null)
random = new Random();
else
random = new Random(seed.hashCode());
}
}
QueryResponseWriterUtil
package org.apache.solr.response;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import org.apache.solr.common.util.ContentStreamBase;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.util.FastWriter;
public final class QueryResponseWriterUtil
{
public static void writeQueryResponse(OutputStream outputStream, QueryResponseWriter responseWriter, SolrQueryRequest solrRequest, SolrQueryResponse solrResponse, String contentType)
throws IOException
{
if ((responseWriter instanceof BinaryQueryResponseWriter)) {
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter)responseWriter;
binWriter.write(outputStream, solrRequest, solrResponse);
} else {
OutputStream out = new OutputStream()
{
public void write(int b) throws IOException {
this.val$outputStream.write(b);
}
public void flush()
throws IOException
{
}
};
Writer writer = buildWriter(out, ContentStreamBase.getCharsetFromContentType(contentType));
responseWriter.write(writer, solrRequest, solrResponse);
writer.flush();
}
}
private static Writer buildWriter(OutputStream outputStream, String charset) throws UnsupportedEncodingException {
Writer writer = charset == null ? new OutputStreamWriter(outputStream, StandardCharsets.UTF_8) : new OutputStreamWriter(outputStream, charset);
return new FastWriter(writer);
}
}
總結
查看源碼,一方面是想知道solr在處理請求的時候有那些過程,另一方面是爲了實際開發做準備。
//獲取CoreContainer容器
CoreContainer coreContainer=(CoreContainer)customerServletRequest.getAttribute("org.apache.solr.CoreContainer");
//獲取對應的solrcore
Solrcore core = coreContainer.getCore("my_solr");
//獲取SolrConfig對象
SolrConfig config = core.getSolrConfig();
//獲取SolrRequestParsers解析對象
SolrRequestParsers parser = config.getRequestParsers();
//得到查詢請求對象
//實際開發中可以根據自己的需求來處理獲取對應的查詢對象
SolrQueryRequest solrReq = parser.parse(this.core, "select", this.req);
//實例化SolrQueryResponse
SolrQueryResponse solrRsp = new SolrQueryResponse();
//獲取對應handler處理器
SolrRequestHandler handler = core.getRequestHandler("/coustomerHandler");
//設置查詢參數
ModifiableSolrParams params = new ModifiableSolrParams(solrReq
.getParams());
solrReq.setParams(params );
//執行查詢
solrReq.getCore().execute(handler, solrReq , solrRsp );
// 判斷是否出現異常
solrRsp.getException()==null
//獲取QueryResponseWriter
//實際開發過程中,可以自己去實現自己的writer。對應solrconfig.xml中的配置
//<queryResponseWriter name="upxiaofeng" class="com.upxiaofeng.solr.CustomerResponseWriter">
//<str name="content-type">text/plain; charset=UTF-8</str>
//</queryResponseWriter>
public final QueryResponseWriter getQueryResponseWriter(String writerName)
QueryResponseWriter responseWriter = core.getQueryResponseWriter("upxiaofeng");
public final QueryResponseWriter getQueryResponseWriter(SolrQueryRequest request)
QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq );
//響應
重寫一下writeResponse方法