From 33bcabc9f6b6f3d9ecd305a38e5d92390ad3fea1 Mon Sep 17 00:00:00 2001 From: Shalin Shekhar Mangar Date: Fri, 24 Apr 2009 06:30:55 +0000 Subject: [PATCH] SOLR-1106 -- Made CoreAdminHandler Actions pluggable so that additional actions may be plugged in or the existing ones can be overridden if needed. git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@768165 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES.txt | 3 + .../org/apache/solr/core/CoreContainer.java | 28 +- .../apache/solr/core/SolrResourceLoader.java | 27 ++ .../solr/handler/admin/CoreAdminHandler.java | 454 ++++++++++++------ 4 files changed, 359 insertions(+), 153 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c1bb9fd9c41..c1ee9117de0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -205,6 +205,9 @@ New Features FieldAnalysisRequestHandler and DocumentAnalysisRequestHandler is also provided in the Solrj client. (Uri Boness, shalin) +38. SOLR-1106: Made CoreAdminHandler Actions pluggable so that additional actions may be plugged in or the existing + ones can be overridden if needed. (Kay Kay, Noble Paul, shalin) + 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 917b940b441..1304fe42f65 100644 --- a/src/java/org/apache/solr/core/CoreContainer.java +++ b/src/java/org/apache/solr/core/CoreContainer.java @@ -174,6 +174,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 ); managementPath = cfg.get("solr/cores/@managementPath", null ); if (libDir != null) { @@ -182,8 +183,12 @@ public class CoreContainer libLoader = SolrResourceLoader.createClassLoader(f, null); } - if( adminPath != null ) { - coreAdminHandler = this.createMultiCoreHandler(); + if (adminPath != null) { + if (adminHandler == null) { + coreAdminHandler = new CoreAdminHandler(this); + } else { + coreAdminHandler = this.createMultiCoreHandler(adminHandler); + } } try { @@ -506,15 +511,18 @@ public class CoreContainer * Creates a CoreAdminHandler for this MultiCore. * @return a CoreAdminHandler */ - protected CoreAdminHandler createMultiCoreHandler() { - return new CoreAdminHandler() { - @Override - public CoreContainer getCoreContainer() { - return CoreContainer.this; - } - }; + protected CoreAdminHandler createMultiCoreHandler(final String adminHandlerClass) { + SolrResourceLoader loader = new SolrResourceLoader(null, libLoader, null); + Object obj = loader.newAdminHandlerInstance(CoreContainer.this, adminHandlerClass); + if ( !(obj instanceof CoreAdminHandler)) + { + throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, + "adminHandlerClass is not of type "+ CoreAdminHandler.class ); + + } + return (CoreAdminHandler) obj; } - + public CoreAdminHandler getMultiCoreHandler() { return coreAdminHandler; } diff --git a/src/java/org/apache/solr/core/SolrResourceLoader.java b/src/java/org/apache/solr/core/SolrResourceLoader.java index 0b0740bf493..c82dec3d71d 100644 --- a/src/java/org/apache/solr/core/SolrResourceLoader.java +++ b/src/java/org/apache/solr/core/SolrResourceLoader.java @@ -348,6 +348,33 @@ public class SolrResourceLoader implements ResourceLoader return obj; } + public Object newAdminHandlerInstance(final CoreContainer coreContainer, String cname, String ... subpackages) { + Class clazz = findClass(cname,subpackages); + if( clazz == null ) { + throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, + "Can not find class: "+cname + " in " + classLoader, false); + } + + Object obj = null; + try { + Constructor ctor = clazz.getConstructor(CoreContainer.class); + obj = ctor.newInstance(coreContainer); + } + catch (Exception e) { + throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, + "Error instantiating class: '" + clazz.getName()+"'", e, false ); + } + //TODO: Does SolrCoreAware make sense here since in a multi-core context + // which core are we talking about ? + if( obj instanceof ResourceLoaderAware ) { + assertAwareCompatibility( ResourceLoaderAware.class, obj ); + waitingForResources.add( (ResourceLoaderAware)obj ); + } + return obj; + } + + + public Object newInstance(String cName, String [] subPackages, Class[] params, Object[] args){ Class clazz = findClass(cName,subPackages); if( clazz == null ) { diff --git a/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java b/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java index 72234ee7d5a..571f6414de2 100644 --- a/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java +++ b/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java @@ -17,197 +17,365 @@ package org.apache.solr.handler.admin; -import java.io.IOException; -import java.io.File; -import java.util.Date; - import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CoreAdminParams; -import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction; +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.core.CoreContainer; -import org.apache.solr.core.SolrCore; import org.apache.solr.core.CoreDescriptor; +import org.apache.solr.core.SolrCore; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryResponse; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.util.RefCounted; +import java.io.File; +import java.io.IOException; +import java.util.Date; + /** * @version $Id$ * @since solr 1.3 */ -public abstract class CoreAdminHandler extends RequestHandlerBase -{ - public CoreAdminHandler() - { +public class CoreAdminHandler extends RequestHandlerBase { + protected final CoreContainer coreContainer; + + public CoreAdminHandler() { super(); // Unlike most request handlers, CoreContainer initialization // should happen in the constructor... + this.coreContainer = null; } - - + + + /** + * Overloaded ctor to inject CoreContainer into the handler. + * + * @param coreContainer Core Container of the solr webapp installed. + */ + public CoreAdminHandler(final CoreContainer coreContainer) { + this.coreContainer = coreContainer; + } + + @Override final public void init(NamedList args) { - throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, - "CoreAdminHandler should not be configured in solrconf.xml\n"+ - "it is a special Handler configured directly by the RequestDispatcher" ); + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, + "CoreAdminHandler should not be configured in solrconf.xml\n" + + "it is a special Handler configured directly by the RequestDispatcher"); } - + /** - * The instance of CoreContainer this handler handles. - * This should be the CoreContainer instance that created this handler. + * The instance of CoreContainer this handler handles. This should be the CoreContainer instance that created this + * handler. + * * @return a CoreContainer instance */ - public abstract CoreContainer getCoreContainer(); - + public CoreContainer getCoreContainer() { + return this.coreContainer; + } + @Override - public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception - { + public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { // Make sure the cores is enabled CoreContainer cores = getCoreContainer(); - if( cores == null ) { - throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, - "Core container instance missing" ); + if (cores == null) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, + "Core container instance missing"); } - boolean do_persist = false; - + boolean doPersist = false; + // Pick the action SolrParams params = req.getParams(); - SolrParams required = params.required(); CoreAdminAction action = CoreAdminAction.STATUS; - String a = params.get( CoreAdminParams.ACTION ); - if( a != null ) { - action = CoreAdminAction.get( a ); - if( action == null ) { - throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, - "Unknown 'action' value. Use: "+CoreAdminAction.values() ); + String a = params.get(CoreAdminParams.ACTION); + if (a != null) { + action = CoreAdminAction.get(a); + if (action == null) { + doPersist = this.handleCustomAction(req, rsp); } } - String cname = params.get( CoreAdminParams.CORE ); - - switch(action) { - case CREATE: { - String name = params.get(CoreAdminParams.NAME); - CoreDescriptor dcore = new CoreDescriptor(cores, name, params.get(CoreAdminParams.INSTANCE_DIR)); - - // fillup optional parameters - String opts = params.get(CoreAdminParams.CONFIG); - if (opts != null) - dcore.setConfigName(opts); - - opts = params.get(CoreAdminParams.SCHEMA); - if (opts != null) - dcore.setSchemaName(opts); - - opts = params.get(CoreAdminParams.DATA_DIR); - if (opts != null) - dcore.setDataDir(opts); - - SolrCore core = cores.create(dcore); - cores.register(name, core,false); - rsp.add("core", core.getName()); - do_persist = cores.isPersistent(); - break; - } - - case RENAME: { - String name = params.get(CoreAdminParams.OTHER); - if (cname.equals(name)) break; - - SolrCore core = cores.getCore(cname); - if (core != null) { - do_persist = cores.isPersistent(); - cores.register(name, core, false); - cores.remove(cname); - core.close(); + if (action != null) { + switch (action) { + case CREATE: { + doPersist = this.handleCreateAction(req, rsp); + break; } - break; - } - case ALIAS: { - String name = params.get(CoreAdminParams.OTHER); - if (cname.equals(name)) break; - - SolrCore core = cores.getCore(cname); - if (core != null) { - do_persist = cores.isPersistent(); - cores.register(name, core, false); - // no core.close() since each entry in the cores map should increase the ref + case RENAME: { + doPersist = this.handleRenameAction(req, rsp); + break; } - break; - } - case UNLOAD: { - SolrCore core = cores.remove(cname); - core.close(); - do_persist = cores.isPersistent(); - break; - } - - case STATUS: { - NamedList status = new SimpleOrderedMap(); - if( cname == null ) { - for (String name : cores.getCoreNames()) { - status.add(name, getCoreStatus( cores, name ) ); - } - } - else { - status.add(cname, getCoreStatus( cores, cname ) ); + case ALIAS: { + doPersist = this.handleAliasAction(req, rsp); + break; } - rsp.add( "status", status ); - do_persist = false; // no state change - break; - - } - - case PERSIST: { - String fileName = params.get( CoreAdminParams.FILE ); - if (fileName != null) { - File file = new File(cores.getConfigFile().getParentFile(), fileName); - cores.persistFile(file); - rsp.add("saved", file.getAbsolutePath()); - do_persist = false; + + case UNLOAD: { + doPersist = this.handleUnloadAction(req, rsp); + break; } - else if (!cores.isPersistent()) { - throw new SolrException (SolrException.ErrorCode.FORBIDDEN, "Persistence is not enabled"); + + case STATUS: { + doPersist = this.handleStatusAction(req, rsp); + break; + } - else - do_persist = true; - break; - } - case RELOAD: { - cores.reload( cname ); - do_persist = false; // no change on reload - break; - } + case PERSIST: { + doPersist = this.handlePersistAction(req, rsp); + break; + } - case SWAP: { - do_persist = params.getBool(CoreAdminParams.PERSISTENT, cores.isPersistent()); - String other = required.get( CoreAdminParams.OTHER ); - cores.swap( cname, other ); - break; - } + case RELOAD: { + doPersist = this.handleReloadAction(req, rsp); + break; + } - default: { - throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, - "TODO: IMPLEMENT: " + action ); - } - } // switch - + case SWAP: { + doPersist = this.handleSwapAction(req, rsp); + break; + } + + default: { + doPersist = this.handleCustomAction(req, rsp); + break; + } + } // switch + } // Should we persist the changes? - if (do_persist) { + if (doPersist) { cores.persist(); rsp.add("saved", cores.getConfigFile().getAbsolutePath()); } } - - private static NamedList getCoreStatus(CoreContainer cores, String cname ) throws IOException - { + + /** + * Handle Custom Action. + *

+ * This method could be overridden by derived classes to handle custom actions.
By default - this method throws a + * solr exception. Derived classes are free to write their derivation if necessary. + */ + protected boolean handleCustomAction(SolrQueryRequest req, SolrQueryResponse rsp) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unsupported operation: " + + req.getParams().get(CoreAdminParams.ACTION)); + } + + /** + * Handle 'CREATE' action. + * + * @param req + * @param rsp + * + * @return persistence flag as necessary. + * + * @throws SolrException in case of a configuration error. + */ + protected boolean handleCreateAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException { + try { + SolrParams params = req.getParams(); + String name = params.get(CoreAdminParams.NAME); + CoreDescriptor dcore = new CoreDescriptor(coreContainer, name, params.get(CoreAdminParams.INSTANCE_DIR)); + + // fillup optional parameters + String opts = params.get(CoreAdminParams.CONFIG); + if (opts != null) + dcore.setConfigName(opts); + + opts = params.get(CoreAdminParams.SCHEMA); + if (opts != null) + dcore.setSchemaName(opts); + + opts = params.get(CoreAdminParams.DATA_DIR); + if (opts != null) + dcore.setDataDir(opts); + + SolrCore core = coreContainer.create(dcore); + coreContainer.register(name, core, false); + rsp.add("core", core.getName()); + return coreContainer.isPersistent(); + } catch (Exception ex) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, + "Error executing default implementation of CREATE", ex); + } + } + + /** + * Handle "RENAME" Action + * + * @param req + * @param rsp + * + * @return + * + * @throws SolrException + */ + protected boolean handleRenameAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException { + SolrParams params = req.getParams(); + + String name = params.get(CoreAdminParams.OTHER); + String cname = params.get(CoreAdminParams.CORE); + boolean doPersist = false; + + if (cname.equals(name)) return doPersist; + + SolrCore core = coreContainer.getCore(cname); + if (core != null) { + doPersist = coreContainer.isPersistent(); + coreContainer.register(name, core, false); + coreContainer.remove(cname); + core.close(); + } + return doPersist; + } + + /** + * Handle "ALIAS" action + * + * @param req + * @param rsp + * + * @return + */ + protected boolean handleAliasAction(SolrQueryRequest req, SolrQueryResponse rsp) { + SolrParams params = req.getParams(); + + String name = params.get(CoreAdminParams.OTHER); + String cname = params.get(CoreAdminParams.CORE); + boolean doPersist = false; + if (cname.equals(name)) return doPersist; + + SolrCore core = coreContainer.getCore(cname); + if (core != null) { + doPersist = coreContainer.isPersistent(); + coreContainer.register(name, core, false); + // no core.close() since each entry in the cores map should increase the ref + } + return doPersist; + } + + + /** + * Handle "UNLOAD" Action + * + * @param req + * @param rsp + * + * @return + */ + protected boolean handleUnloadAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException { + SolrParams params = req.getParams(); + String cname = params.get(CoreAdminParams.CORE); + SolrCore core = coreContainer.remove(cname); + core.close(); + return coreContainer.isPersistent(); + + } + + /** + * Handle "STATUS" action + * + * @param req + * @param rsp + * + * @return + */ + protected boolean handleStatusAction(SolrQueryRequest req, SolrQueryResponse rsp) + throws SolrException { + SolrParams params = req.getParams(); + + String cname = params.get(CoreAdminParams.CORE); + boolean doPersist = false; + NamedList status = new SimpleOrderedMap(); + try { + if (cname == null) { + for (String name : coreContainer.getCoreNames()) { + status.add(name, getCoreStatus(coreContainer, name)); + } + } else { + status.add(cname, getCoreStatus(coreContainer, cname)); + } + rsp.add("status", status); + doPersist = false; // no state change + return doPersist; + } catch (Exception ex) { + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, + "Error handling 'status' action ", ex); + } + } + + /** + * Handler "PERSIST" action + * + * @param req + * @param rsp + * + * @return + * + * @throws SolrException + */ + protected boolean handlePersistAction(SolrQueryRequest req, SolrQueryResponse rsp) + throws SolrException { + SolrParams params = req.getParams(); + boolean doPersist = false; + String fileName = params.get(CoreAdminParams.FILE); + if (fileName != null) { + File file = new File(coreContainer.getConfigFile().getParentFile(), fileName); + coreContainer.persistFile(file); + rsp.add("saved", file.getAbsolutePath()); + doPersist = false; + } else if (!coreContainer.isPersistent()) { + throw new SolrException(SolrException.ErrorCode.FORBIDDEN, "Persistence is not enabled"); + } else + doPersist = true; + + return doPersist; + } + + /** + * Handler "RELOAD" action + * + * @param req + * @param rsp + * + * @return + */ + protected boolean handleReloadAction(SolrQueryRequest req, SolrQueryResponse rsp) { + SolrParams params = req.getParams(); + String cname = params.get(CoreAdminParams.CORE); + try { + coreContainer.reload(cname); + return false; // no change on reload + } catch (Exception ex) { + throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error handling 'reload' action", ex); + } + } + + /** + * Handle "SWAP" action + * + * @param req + * @param rsp + * + * @return + */ + protected boolean handleSwapAction(SolrQueryRequest req, SolrQueryResponse rsp) { + final SolrParams params = req.getParams(); + final SolrParams required = params.required(); + + final String cname = params.get(CoreAdminParams.CORE); + boolean doPersist = params.getBool(CoreAdminParams.PERSISTENT, coreContainer.isPersistent()); + String other = required.get(CoreAdminParams.OTHER); + coreContainer.swap(cname, other); + return doPersist; + + } + + protected static NamedList getCoreStatus(CoreContainer cores, String cname) throws IOException { NamedList info = new SimpleOrderedMap(); SolrCore core = cores.getCore(cname); if (core != null) { @@ -227,15 +395,15 @@ public abstract class CoreAdminHandler extends RequestHandlerBase return info; } - private static String normalizePath(String path) { + protected static String normalizePath(String path) { if (path == null) return null; path = path.replace('/', File.separatorChar); path = path.replace('\\', File.separatorChar); return path; } - - + + //////////////////////// SolrInfoMBeans methods ////////////////////// @Override