You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by sh...@apache.org on 2009/04/24 08:30:56 UTC

svn commit: r768165 - in /lucene/solr/trunk: CHANGES.txt src/java/org/apache/solr/core/CoreContainer.java src/java/org/apache/solr/core/SolrResourceLoader.java src/java/org/apache/solr/handler/admin/CoreAdminHandler.java

Author: shalin
Date: Fri Apr 24 06:30:55 2009
New Revision: 768165

URL: http://svn.apache.org/viewvc?rev=768165&view=rev
Log:
SOLR-1106 -- Made CoreAdminHandler Actions pluggable so that additional actions may be plugged in or the existing ones can be overridden if needed.

Modified:
    lucene/solr/trunk/CHANGES.txt
    lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
    lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java
    lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java

Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=768165&r1=768164&r2=768165&view=diff
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Fri Apr 24 06:30:55 2009
@@ -205,6 +205,9 @@
     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

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java?rev=768165&r1=768164&r2=768165&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java Fri Apr 24 06:30:55 2009
@@ -174,6 +174,7 @@
       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 @@
         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 @@
    * 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;
   }

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java?rev=768165&r1=768164&r2=768165&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java Fri Apr 24 06:30:55 2009
@@ -348,6 +348,33 @@
     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 ) {

Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java?rev=768165&r1=768164&r2=768165&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java Fri Apr 24 06:30:55 2009
@@ -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;
-      }
+    if (action != null) {
+      switch (action) {
+        case CREATE: {
+          doPersist = this.handleCreateAction(req, rsp);
+          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();
+        case RENAME: {
+          doPersist = this.handleRenameAction(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 ALIAS: {
+          doPersist = this.handleAliasAction(req, rsp);
+          break;
         }
-        break;
-      }
 
-      case UNLOAD: {
-        SolrCore core = cores.remove(cname);
-        core.close();
-        do_persist = cores.isPersistent();
-        break;
-      }
+        case UNLOAD: {
+          doPersist = this.handleUnloadAction(req, rsp);
+          break;
+        }
 
-      case STATUS: {
-        NamedList<Object> status = new SimpleOrderedMap<Object>();
-        if( cname == null ) {
-          for (String name : cores.getCoreNames()) {
-            status.add(name, getCoreStatus( cores, name  ) );
-          }
-        } 
-        else {
-          status.add(cname, getCoreStatus( cores, cname  ) );
-        }
-        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;
-        }
-        else if (!cores.isPersistent()) {
-          throw new SolrException (SolrException.ErrorCode.FORBIDDEN, "Persistence is not enabled");
-        }
-        else
-          do_persist = true;
-        break;
-      }
+        case STATUS: {
+          doPersist = this.handleStatusAction(req, rsp);
+          break;
 
-      case RELOAD: {
-        cores.reload( cname  );
-        do_persist = false; // no change on reload
-        break;
-      }
+        }
 
-      case SWAP: {
-        do_persist = params.getBool(CoreAdminParams.PERSISTENT, cores.isPersistent());
-        String other = required.get( CoreAdminParams.OTHER );
-        cores.swap( cname, other );
-        break;
-      } 
-
-      default: {
-        throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,
-            "TODO: IMPLEMENT: " + action );
-      }
-    } // switch
-      
+        case PERSIST: {
+          doPersist = this.handlePersistAction(req, rsp);
+          break;
+        }
+
+        case RELOAD: {
+          doPersist = this.handleReloadAction(req, rsp);
+          break;
+        }
+
+        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<Object> getCoreStatus(CoreContainer cores, String cname ) throws IOException
-  {
+
+  /**
+   * Handle Custom Action.
+   * <p/>
+   * This method could be overridden by derived classes to handle custom actions. <br> 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<Object> status = new SimpleOrderedMap<Object>();
+    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<Object> getCoreStatus(CoreContainer cores, String cname) throws IOException {
     NamedList<Object> info = new SimpleOrderedMap<Object>();
     SolrCore core = cores.getCore(cname);
     if (core != null) {
@@ -227,15 +395,15 @@
     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