diff --git a/CHANGES.txt b/CHANGES.txt index 79606a0b704..b78810ea3d8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -215,6 +215,8 @@ New Features 50. SOLR-1110: Support sorting on trie fields with Distributed Search. (Mark Miller, Uwe Schindler via shalin) +51. SOLR-1121: CoreAdminhandler should not need a core . This makes it possible to start a Solr server w/o a core .(noble) + Optimizations ---------------------- 1. SOLR-374: Use IndexReader.reopen to save resources by re-using parts of the diff --git a/src/java/org/apache/solr/core/CoreContainer.java b/src/java/org/apache/solr/core/CoreContainer.java index 1304fe42f65..ab5b9809606 100644 --- a/src/java/org/apache/solr/core/CoreContainer.java +++ b/src/java/org/apache/solr/core/CoreContainer.java @@ -66,7 +66,6 @@ public class CoreContainer protected SolrResourceLoader loader = null; protected java.lang.ref.WeakReference adminCore = null; protected Properties containerProperties; - public CoreContainer() { } @@ -174,7 +173,7 @@ public class CoreContainer persistent = cfg.getBool( "solr/@persistent", false ); libDir = cfg.get( "solr/@sharedLib", null); adminPath = cfg.get( "solr/cores/@adminPath", null ); - String adminHandler = cfg.get( "solr/cores/@adminHandler", null ); + String adminHandler = cfg.get( "solr/cores/@adminHandler", null ); managementPath = cfg.get("solr/cores/@managementPath", null ); if (libDir != null) { @@ -475,6 +474,7 @@ public class CoreContainer /** * Sets the preferred core used to handle MultiCore admin tasks. */ + @Deprecated public void setAdminCore(SolrCore core) { synchronized (cores) { adminCore = new java.lang.ref.WeakReference(core); @@ -486,7 +486,8 @@ public class CoreContainer * increase its refcount. * @see SolrCore#close() * @return the acquired admin core, null if no core is available - */ + */ + @Deprecated public SolrCore getAdminCore() { synchronized (cores) { SolrCore core = adminCore != null ? adminCore.get() : null; diff --git a/src/java/org/apache/solr/core/SolrCore.java b/src/java/org/apache/solr/core/SolrCore.java index c79fe730653..5135e4927ac 100644 --- a/src/java/org/apache/solr/core/SolrCore.java +++ b/src/java/org/apache/solr/core/SolrCore.java @@ -22,7 +22,6 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FSDirectory; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams.EchoParamStyle; @@ -1354,7 +1353,7 @@ public final class SolrCore implements SolrInfoMBean { execute(handler, req, rsp); } - protected void setResponseHeaderValues(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryResponse rsp) { + public static void setResponseHeaderValues(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryResponse rsp) { // TODO should check that responseHeader has not been replaced by handler NamedList responseHeader = rsp.getResponseHeader(); final int qtime=(int)(rsp.getEndTime() - req.getStartTime()); @@ -1401,8 +1400,20 @@ public final class SolrCore implements SolrInfoMBean { private QueryResponseWriter defaultResponseWriter; private final Map responseWriters = new HashMap(); + public static final Map DEFAULT_RESPONSE_WRITERS ; + static{ + HashMap m= new HashMap(); + m.put("xml", new XMLResponseWriter()); + m.put("standard", m.get("xml")); + m.put("json", new JSONResponseWriter()); + m.put("python", new PythonResponseWriter()); + m.put("ruby", new RubyResponseWriter()); + m.put("raw", new RawResponseWriter()); + m.put("javabin", new BinaryResponseWriter()); + DEFAULT_RESPONSE_WRITERS = Collections.unmodifiableMap(m); + } - /** Configure the query response writers. There will always be a default writer; additional + /** Configure the query response writers. There will always be a default writer; additional * writers may also be configured. */ private void initWriters() { String xpath = "queryResponseWriter"; @@ -1412,31 +1423,15 @@ public final class SolrCore implements SolrInfoMBean { new NamedListPluginLoader( "[solrconfig.xml] "+xpath, responseWriters ); defaultResponseWriter = loader.load( solrConfig.getResourceLoader(), nodes ); + for (Map.Entry entry : DEFAULT_RESPONSE_WRITERS.entrySet()) { + if(responseWriters.get(entry.getKey()) == null) responseWriters.put(entry.getKey(), entry.getValue()); + } // configure the default response writer; this one should never be null if (defaultResponseWriter == null) { defaultResponseWriter = responseWriters.get("standard"); - if( defaultResponseWriter == null ) { - defaultResponseWriter = new XMLResponseWriter(); - } } - // make JSON response writers available by default - if (responseWriters.get("json")==null) { - responseWriters.put("json", new JSONResponseWriter()); - } - if (responseWriters.get("python")==null) { - responseWriters.put("python", new PythonResponseWriter()); - } - if (responseWriters.get("ruby")==null) { - responseWriters.put("ruby", new RubyResponseWriter()); - } - if (responseWriters.get("raw")==null) { - responseWriters.put("raw", new RawResponseWriter()); - } - if (responseWriters.get("javabin") == null) { - responseWriters.put("javabin", new BinaryResponseWriter()); - } } /** Finds a writer by name, or returns the default writer if not found. */ diff --git a/src/java/org/apache/solr/request/SolrQueryRequestBase.java b/src/java/org/apache/solr/request/SolrQueryRequestBase.java index 66b6ac5db90..4dcaafea614 100644 --- a/src/java/org/apache/solr/request/SolrQueryRequestBase.java +++ b/src/java/org/apache/solr/request/SolrQueryRequestBase.java @@ -200,6 +200,7 @@ public abstract class SolrQueryRequestBase implements SolrQueryRequest { // The index searcher associated with this request protected RefCounted searcherHolder; public SolrIndexSearcher getSearcher() { + if(core == null) return null;//a request for a core admin will no have a core // should this reach out and get a searcher from the core singleton, or // should the core populate one in a factory method to create requests? // or there could be a setSearcher() method that Solr calls @@ -218,7 +219,8 @@ public abstract class SolrQueryRequestBase implements SolrQueryRequest { // The index schema associated with this request public IndexSchema getSchema() { - return core.getSchema(); + //a request for a core admin will no have a core + return core == null? null: core.getSchema(); } /** diff --git a/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java b/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java index 612825b7203..eeb29d66d4f 100644 --- a/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java +++ b/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java @@ -20,6 +20,7 @@ package org.apache.solr.servlet; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.ByteArrayInputStream; import java.util.WeakHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,6 +35,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.solr.common.SolrException; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.params.CommonParams; import org.apache.solr.core.*; import org.apache.solr.request.*; @@ -53,7 +56,17 @@ public class SolrDispatchFilter implements Filter protected String pathPrefix = null; // strip this from the beginning of a path protected String abortErrorMessage = null; protected String solrConfigFilename = null; - protected final WeakHashMap parsers = new WeakHashMap(); + protected final WeakHashMap parsers = new WeakHashMap(); + protected final SolrRequestParsers adminRequestParser; + + public SolrDispatchFilter() { + try { + adminRequestParser = new SolrRequestParsers(new Config(null,"solr",new ByteArrayInputStream("".getBytes()),"") ); + } catch (Exception e) { + //unlikely + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,e); + } + } public void init(FilterConfig config) throws ServletException { @@ -156,12 +169,10 @@ public class SolrDispatchFilter implements Filter // Check for the core admin page if( path.equals( cores.getAdminPath() ) ) { handler = cores.getMultiCoreHandler(); - // pick a core to use for output generation - core = cores.getAdminCore(); - if( core == null ) { - throw new RuntimeException( "Can not find a valid core for the cores admin handler" ); - } - } + solrReq = adminRequestParser.parse(null,path, req); + handleAdminRequest(req, response, handler, solrReq); + return; + } else { //otherwise, we should find a core from the path idx = path.indexOf( "/", 1 ); @@ -187,7 +198,7 @@ public class SolrDispatchFilter implements Filter parser = parsers.get(core); if( parser == null ) { parser = new SolrRequestParsers(config); - parsers.put( core, parser ); + parsers.put( core.getSolrConfig(), parser ); } // Determine the handler from the url path if not set @@ -241,26 +252,8 @@ public class SolrDispatchFilter implements Filter } catch (ClassCastException cce) { log.log(Level.WARNING, "exception adding response header log information", cce); }*/ - if( solrRsp.getException() != null ) { - sendError( (HttpServletResponse)response, solrRsp.getException() ); - } - else { - // Now write it out - QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq); - response.setContentType(responseWriter.getContentType(solrReq, solrRsp)); - if (Method.HEAD != reqMethod) { - if (responseWriter instanceof BinaryQueryResponseWriter) { - BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter; - binWriter.write(response.getOutputStream(), solrReq, solrRsp); - } else { - PrintWriter out = response.getWriter(); - responseWriter.write(out, solrReq, solrRsp); - - } - - } - //else http HEAD request, nothing to write out, waited this long just to get ContentType - } + QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq); + writeResponse(solrRsp, response, responseWriter, solrReq, reqMethod); } return; // we are done with a valid handler } @@ -295,6 +288,50 @@ public class SolrDispatchFilter implements Filter chain.doFilter(request, response); } + private void handleAdminRequest(HttpServletRequest req, ServletResponse response, SolrRequestHandler handler, + SolrQueryRequest solrReq) throws IOException { + SolrQueryResponse solrResp = new SolrQueryResponse(); + final NamedList responseHeader = new SimpleOrderedMap(); + solrResp.add("responseHeader", responseHeader); + NamedList toLog = solrResp.getToLog(); + toLog.add("webapp", req.getContextPath()); + toLog.add("path", solrReq.getContext().get("path")); + toLog.add("params", "{" + solrReq.getParamString() + "}"); + handler.handleRequest(solrReq, solrResp); + SolrCore.setResponseHeaderValues(handler, solrReq, solrResp); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < toLog.size(); i++) { + String name = toLog.getName(i); + Object val = toLog.getVal(i); + sb.append(name).append("=").append(val).append(" "); + } + QueryResponseWriter respWriter = SolrCore.DEFAULT_RESPONSE_WRITERS.get(solrReq.getParams().get(CommonParams.WT)); + if (respWriter == null) respWriter = SolrCore.DEFAULT_RESPONSE_WRITERS.get("standard"); + writeResponse(solrResp, response, respWriter, solrReq, Method.getMethod(req.getMethod())); + } + + private void writeResponse(SolrQueryResponse solrRsp, ServletResponse response, + QueryResponseWriter responseWriter, SolrQueryRequest solrReq, Method reqMethod) + throws IOException { + if (solrRsp.getException() != null) { + sendError((HttpServletResponse) response, solrRsp.getException()); + } else { + // Now write it out + response.setContentType(responseWriter.getContentType(solrReq, solrRsp)); + if (Method.HEAD != reqMethod) { + if (responseWriter instanceof BinaryQueryResponseWriter) { + BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter; + binWriter.write(response.getOutputStream(), solrReq, solrRsp); + } else { + PrintWriter out = response.getWriter(); + responseWriter.write(out, solrReq, solrRsp); + + } + } + //else http HEAD request, nothing to write out, waited this long just to get ContentType + } + } + protected void execute( HttpServletRequest req, SolrRequestHandler handler, SolrQueryRequest sreq, SolrQueryResponse rsp) { // a custom filter could add more stuff to the request before passing it on. // for example: sreq.getContext().put( "HttpServletRequest", req );