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 ry...@apache.org on 2007/07/03 08:10:11 UTC

svn commit: r552680 - in /lucene/solr/trunk: ./ src/java/org/apache/solr/core/ src/java/org/apache/solr/handler/ src/java/org/apache/solr/request/ src/java/org/apache/solr/schema/ src/java/org/apache/solr/util/ src/java/org/apache/solr/util/plugin/

Author: ryan
Date: Mon Jul  2 23:10:10 2007
New Revision: 552680

URL: http://svn.apache.org/viewvc?view=rev&rev=552680
Log:
SOLR-260 -- adding a standard PluginLoader framework.  NOTE, this commit includes parts of files from (the soon to be commited) highlight plugins SOLR-225

Added:
    lucene/solr/trunk/src/java/org/apache/solr/util/plugin/
    lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java   (with props)
    lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java   (with props)
    lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java   (with props)
    lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java   (with props)
    lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java   (with props)
Modified:
    lucene/solr/trunk/CHANGES.txt
    lucene/solr/trunk/src/java/org/apache/solr/core/RequestHandlers.java
    lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java
    lucene/solr/trunk/src/java/org/apache/solr/core/SolrInfoMBean.java
    lucene/solr/trunk/src/java/org/apache/solr/handler/DisMaxRequestHandler.java
    lucene/solr/trunk/src/java/org/apache/solr/handler/StandardRequestHandler.java
    lucene/solr/trunk/src/java/org/apache/solr/request/QueryResponseWriter.java
    lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java
    lucene/solr/trunk/src/java/org/apache/solr/util/SolrPluginUtils.java

Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Mon Jul  2 23:10:10 2007
@@ -83,6 +83,10 @@
     parsed and before they are committed to the index.  This is a good place
     for custom document manipulation or document based authorization. (ryan)
 
+13. SOLR-260: Converting to a standard PluginLoader framework.  This reworks
+    RequestHandlers, FieldTypes, and QueryResponseWriters to share the same
+    base code for loading and initalizing plugins. (ryan)
+
 Changes in runtime behavior
 
 Optimizations

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/RequestHandlers.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/RequestHandlers.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/RequestHandlers.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/RequestHandlers.java Mon Jul  2 23:10:10 2007
@@ -20,7 +20,6 @@
 import java.net.URL;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.logging.Logger;
 
@@ -34,8 +33,9 @@
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryResponse;
 import org.apache.solr.request.SolrRequestHandler;
-import org.w3c.dom.Node;
+import org.apache.solr.util.plugin.AbstractPluginLoader;
 import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
 
 /**
  * @author yonik
@@ -46,7 +46,7 @@
   public static final String DEFAULT_HANDLER_NAME="standard";
 
   // Use a synchronized map - since the handlers can be changed at runtime, 
-  // the map implementaion should be thread safe
+  // the map implementation should be thread safe
   private final Map<String, SolrRequestHandler> handlers = Collections.synchronizedMap(
       new HashMap<String,SolrRequestHandler>() );
 
@@ -75,8 +75,8 @@
   }
 
   /**
-   * Handlers must be initalized before calling this function.  As soon as this is
-   * called, the handler can immediatly accept requests.
+   * Handlers must be initialized before calling this function.  As soon as this is
+   * called, the handler can immediately accept requests.
    * 
    * This call is thread safe.
    * 
@@ -97,7 +97,7 @@
   }
 
   /**
-   * Returns an unmodifieable Map containing the registered handlers
+   * Returns an unmodifiable Map containing the registered handlers
    */
   public Map<String,SolrRequestHandler> getRequestHandlers() {
     return Collections.unmodifiableMap( handlers );
@@ -110,96 +110,73 @@
    * This function should <b>only</b> be called from the SolrCore constructor.  It is
    * not intended as a public API.
    * 
-   * While the normal runtime registration contract is that handlers MUST be initalizad 
+   * While the normal runtime registration contract is that handlers MUST be initialized 
    * before they are registered, this function does not do that exactly.
    * 
-   * This funciton registers all handlers first and then calls init() for each one.  
+   * This function registers all handlers first and then calls init() for each one.  
    * 
    * This is OK because this function is only called at startup and there is no chance that
-   * a handler could be asked to handle a request before it is initalized.
+   * a handler could be asked to handle a request before it is initialized.
    * 
    * The advantage to this approach is that handlers can know what path they are registered
-   * to and what other handlers are avaliable at startup.
+   * to and what other handlers are available at startup.
    * 
-   * Handlers will be registered and initalized in the order they appear in solrconfig.xml
+   * Handlers will be registered and initialized in the order they appear in solrconfig.xml
    */
-  @SuppressWarnings("unchecked")
   void initHandlersFromConfig( Config config )  
   {
-    NodeList nodes = (NodeList)config.evaluate("requestHandler", XPathConstants.NODESET);
-    
-    if (nodes !=null ) {
-      // make sure it only once/handler and that that handlers get initalized in the 
-      // order they were defined
-      Map<String,NamedList<Object>> names = new LinkedHashMap<String,NamedList<Object>>(); 
-      for (int i=0; i<nodes.getLength(); i++) {
-        Node node = nodes.item(i);
-  
-        // In a production environment, we can tolerate an error in some request handlers, 
-        // still load the others, and have a working system.
-        try {
-          String name = DOMUtil.getAttr(node,"name","requestHandler config");
-          String className = DOMUtil.getAttr(node,"class","requestHandler config");
-          String startup = DOMUtil.getAttr(node,"startup", null );
-          NamedList<Object> args = DOMUtil.childNodesToNamedList(node);
-  
-          // Perhaps lazy load the request handler with a wrapper
-          SolrRequestHandler handler = null;
+    final RequestHandlers handlers = this;
+    AbstractPluginLoader<SolrRequestHandler> loader = 
+      new AbstractPluginLoader<SolrRequestHandler>( "[solrconfig.xml] requestHandler", true )
+    {
+      @Override
+      protected SolrRequestHandler create( String name, String className, Map<String,String> params, Node node ) throws Exception
+      {
+        String startup = params.get( "startup" );
+        if( startup != null ) {
           if( "lazy".equals( startup ) ) {
-            log.info("adding lazy requestHandler: " + name + "=" + className);
-            handler = new LazyRequestHandlerWrapper( className, args );
+            log.info("adding lazy requestHandler: " + className );
+            NamedList args = DOMUtil.childNodesToNamedList(node);
+            return new LazyRequestHandlerWrapper( className, args );
           }
           else {
-            Class<? extends SolrRequestHandler> clazz = Config.findClass( className, new String[]{} );
-            log.info("adding requestHandler: " + name + "=" + className);
-            handler = clazz.newInstance();
-          }
-          
-          SolrRequestHandler old = register( name, handler );
-          if( old != null ) {
-            String msg = "multiple handlers registered on the same path! ignoring: "+old;
-            Throwable t = new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
-            SolrConfig.severeErrors.add( t );
-            SolrException.logOnce(log,null,t);
+            throw new Exception( "Unknown startup value: '"+startup+"' for: "+className );
           }
-          names.put( name, args );
-        } 
-        catch (Exception e) {
-          SolrConfig.severeErrors.add( e );
-          SolrException.logOnce(log,null,e);
         }
+        return super.create( name, className, params, node );
       }
-      
-      // Call init() on each handler after they have all been registered
-      for( Map.Entry<String, NamedList<Object>> reg : names.entrySet() ) {
-        try {
-          handlers.get( reg.getKey() ).init( reg.getValue() );
-        }
-        catch( Exception e ) {
-          SolrConfig.severeErrors.add( e );
-          SolrException.logOnce(log,null,e);
-        }
+
+      @Override
+      protected SolrRequestHandler register(String name, SolrRequestHandler plugin) throws Exception {
+        return handlers.register( name, plugin );
       }
-    }
+      
+      @Override
+      protected void init(SolrRequestHandler plugin, Map<String, String> params, Node node ) throws Exception {
+        plugin.init( DOMUtil.childNodesToNamedList(node) );
+      }      
+    };
     
-    //
-    // Get the default handler and add it in the map under null and empty
-    // to act as the default.
-    //
-    SolrRequestHandler handler = get(RequestHandlers.DEFAULT_HANDLER_NAME);
-    if (handler == null) {
-      handler = new StandardRequestHandler();
-      register(RequestHandlers.DEFAULT_HANDLER_NAME, handler);
+    NodeList nodes = (NodeList)config.evaluate("requestHandler", XPathConstants.NODESET);
+    
+    // Load the handlers and get the default one
+    SolrRequestHandler defaultHandler = loader.load( nodes );
+    if( defaultHandler == null ) {
+      defaultHandler = get(RequestHandlers.DEFAULT_HANDLER_NAME);
+      if( defaultHandler == null ) {
+        defaultHandler = new StandardRequestHandler();
+        register(RequestHandlers.DEFAULT_HANDLER_NAME, defaultHandler);
+      }
     }
-    register(null, handler);
-    register("", handler);
+    register(null, defaultHandler);
+    register("", defaultHandler);
   }
     
 
   /**
    * The <code>LazyRequestHandlerWrapper</core> wraps any {@link SolrRequestHandler}.  
    * Rather then instanciate and initalize the handler on startup, this wrapper waits
-   * untill it is actually called.  This should only be used for handlers that are
+   * until it is actually called.  This should only be used for handlers that are
    * unlikely to be used in the normal lifecycle.
    * 
    * You can enable lazy loading in solrconfig.xml using:
@@ -227,7 +204,7 @@
     {
       _className = className;
       _args = args;
-      _handler = null; // don't initalize
+      _handler = null; // don't initialize
     }
     
     /**
@@ -238,7 +215,7 @@
     }
     
     /**
-     * Wait for the first request before initalizing the wrapped handler 
+     * Wait for the first request before initializing the wrapped handler 
      */
     public void handleRequest(SolrQueryRequest req, SolrQueryResponse rsp)  {
       getWrappedHandler().handleRequest( req, rsp );
@@ -319,11 +296,13 @@
         return _handler.getStatistics();
       }
       NamedList<String> lst = new SimpleOrderedMap<String>();
-      lst.add("note", "not initaized yet" );
+      lst.add("note", "not initialized yet" );
       return lst;
     }
   }
 }
+
+
 
 
 

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java Mon Jul  2 23:10:10 2007
@@ -42,6 +42,7 @@
 import org.apache.solr.common.util.DOMUtil;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.highlight.SolrHighlighter;
 import org.apache.solr.request.JSONResponseWriter;
 import org.apache.solr.request.PythonResponseWriter;
 import org.apache.solr.request.QueryResponseWriter;
@@ -57,7 +58,7 @@
 import org.apache.solr.update.SolrIndexWriter;
 import org.apache.solr.update.UpdateHandler;
 import org.apache.solr.util.RefCounted;
-import org.w3c.dom.Element;
+import org.apache.solr.util.plugin.NamedListPluginLoader;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
@@ -79,7 +80,8 @@
   private final UpdateHandler updateHandler;
   private static final long startTime = System.currentTimeMillis();
   private final RequestHandlers reqHandlers = new RequestHandlers();
-
+  private final SolrHighlighter highlighter;
+  
   public long getStartTime() { return startTime; }
 
   public static SolrIndexConfig mainIndexConfig = new SolrIndexConfig("mainIndex");
@@ -211,6 +213,10 @@
       
       reqHandlers.initHandlersFromConfig( SolrConfig.config );
 
+      // TODO? could select the highlighter implementation
+      highlighter = new SolrHighlighter();
+      highlighter.initalize( SolrConfig.config );
+      
       try {
         // Open the searcher *before* the handler so we don't end up opening
         // one in the middle.
@@ -270,6 +276,13 @@
   }
 
   /**
+   * Get the SolrHighlighter
+   */
+  public SolrHighlighter getHighlighter() {
+    return highlighter;
+  }
+
+  /**
    * Registers a handler at the specified location.  If one exists there, it will be replaced.
    * To remove a handler, register <code>null</code> at its path
    * 
@@ -718,31 +731,18 @@
   private void initWriters() {
     String xpath = "queryResponseWriter";
     NodeList nodes = (NodeList) SolrConfig.config.evaluate(xpath, XPathConstants.NODESET);
-    int length = nodes.getLength();
-    for (int i=0; i<length; i++) {
-      Element elm = (Element) nodes.item(i);
-      
-      try {
-        String name = DOMUtil.getAttr(elm,"name", xpath+" config");
-        String className = DOMUtil.getAttr(elm,"class", xpath+" config");
-        log.info("adding queryResponseWriter "+name+"="+className);
-          
-        QueryResponseWriter writer = (QueryResponseWriter) Config.newInstance(className);
-        writer.init(DOMUtil.childNodesToNamedList(elm));
-        responseWriters.put(name, writer);
-      } catch (Exception ex) {
-        SolrConfig.severeErrors.add( ex );
-        SolrException.logOnce(log,null, ex);
-        // if a writer can't be created, skip it and continue
-      }
-    }
-
+    
+    NamedListPluginLoader<QueryResponseWriter> loader = 
+      new NamedListPluginLoader<QueryResponseWriter>( "[solrconfig.xml] "+xpath, responseWriters );
+    
+    defaultResponseWriter = loader.load( nodes );
+    
     // configure the default response writer; this one should never be null
-    if (responseWriters.containsKey("standard")) {
-      defaultResponseWriter = responseWriters.get("standard");
-    }
     if (defaultResponseWriter == null) {
-      defaultResponseWriter = new XMLResponseWriter();
+      defaultResponseWriter = responseWriters.get("standard");
+      if( defaultResponseWriter == null ) {
+        defaultResponseWriter = new XMLResponseWriter();
+      }
     }
 
     // make JSON response writers available by default

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/SolrInfoMBean.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/SolrInfoMBean.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/SolrInfoMBean.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/SolrInfoMBean.java Mon Jul  2 23:10:10 2007
@@ -20,7 +20,6 @@
 import java.net.URL;
 
 import org.apache.solr.common.util.NamedList;
-import org.apache.solr.util.*;
 
 /**
  * MBean interface for getting various ui friendly strings and URLs
@@ -32,7 +31,7 @@
  */
 public interface SolrInfoMBean {
 
-  public enum Category { CORE, QUERYHANDLER, UPDATEHANDLER, CACHE, OTHER };
+  public enum Category { CORE, QUERYHANDLER, UPDATEHANDLER, CACHE, HIGHLIGHTING, OTHER };
 
   /**
    * Simple common usage name, e.g. BasicQueryHandler,

Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/DisMaxRequestHandler.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/DisMaxRequestHandler.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/DisMaxRequestHandler.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/DisMaxRequestHandler.java Mon Jul  2 23:10:10 2007
@@ -38,6 +38,7 @@
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.highlight.SolrHighlighter;
 import org.apache.solr.request.SimpleFacets;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryResponse;
@@ -356,20 +357,19 @@
         }
 
       } catch (Exception e) {
-        SolrException.logOnce(SolrCore.log,
-                              "Exception during debug", e);
+        SolrException.logOnce(SolrCore.log, "Exception during debug", e);
         rsp.add("exception_during_debug", SolrException.toStr(e));
       }
 
       /* * * Highlighting/Summarizing  * * */
-      if(HighlightingUtils.isHighlightingEnabled(req) && parsedUserQuery != null) {
+      SolrHighlighter highlighter = req.getCore().getHighlighter();
+      if(highlighter.isHighlightingEnabled( params ) && parsedUserQuery != null) {
         String[] highFields = queryFields.keySet().toArray(new String[0]);
-        NamedList sumData =
-          HighlightingUtils.doHighlighting(
-	       results.docList, 
-	       parsedUserQuery.rewrite(req.getSearcher().getReader()), 
-	       req, 
-	       highFields);
+        NamedList sumData = highlighter.doHighlighting(
+  	       results.docList, 
+  	       parsedUserQuery.rewrite(req.getSearcher().getReader()), 
+  	       req, 
+  	       highFields);
         if(sumData != null)
           rsp.add("highlighting", sumData);
       }

Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/StandardRequestHandler.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/StandardRequestHandler.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/handler/StandardRequestHandler.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/handler/StandardRequestHandler.java Mon Jul  2 23:10:10 2007
@@ -36,6 +36,7 @@
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.highlight.SolrHighlighter;
 
 import static org.apache.solr.common.params.SolrParams.*;
 
@@ -161,7 +162,9 @@
         rsp.add("exception_during_debug", SolrException.toStr(e));
       }
       
-      NamedList sumData = HighlightingUtils.doHighlighting(
+
+      SolrHighlighter highlighter = req.getCore().getHighlighter();
+      NamedList sumData = highlighter.doHighlighting(
         results.docList, query.rewrite(req.getSearcher().getReader()), req, new String[]{defaultField});
       if(sumData != null)
         rsp.add("highlighting", sumData);

Modified: lucene/solr/trunk/src/java/org/apache/solr/request/QueryResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/request/QueryResponseWriter.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/request/QueryResponseWriter.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/request/QueryResponseWriter.java Mon Jul  2 23:10:10 2007
@@ -21,6 +21,7 @@
 import java.io.IOException;
 
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.util.plugin.NamedListInitializedPlugin;
 
 /**
  * Implementations of <code>QueryResponseWriter</code> are used to format responses to query requests.
@@ -41,7 +42,7 @@
  * @author yonik
  * @version $Id$
  */
-public interface QueryResponseWriter {
+public interface QueryResponseWriter extends NamedListInitializedPlugin {
   public static String CONTENT_TYPE_XML_UTF8="text/xml; charset=UTF-8";
   public static String CONTENT_TYPE_TEXT_UTF8="text/plain; charset=UTF-8";
   public static String CONTENT_TYPE_TEXT_ASCII="text/plain; charset=US-ASCII";
@@ -68,7 +69,7 @@
    * <p>
    * QueryResponseWriter's must implement this method to return a valid 
    * HTTP Content-Type header for the request, that will logically 
-   * corrispond with the output produced by the write method.
+   * correspond with the output produced by the write method.
    * </p>
    * @return a Content-Type string, which may not be null.
    */
@@ -81,4 +82,6 @@
    */
   public void init(NamedList args);
 }
+
+
 

Modified: lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/schema/IndexSchema.java Mon Jul  2 23:10:10 2007
@@ -31,6 +31,7 @@
 import org.apache.solr.analysis.TokenizerChain;
 import org.apache.solr.analysis.TokenizerFactory;
 import org.apache.solr.search.SolrQueryParser;
+import org.apache.solr.util.plugin.AbstractPluginLoader;
 import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
@@ -295,7 +296,7 @@
 
       Config config = new Config("schema", getInputStream(), "/schema/");
       Document document = config.getDocument();
-      XPath xpath = config.getXPath();
+      final XPath xpath = config.getXPath();
 
       Node nd = (Node) xpath.evaluate("/schema/@name", document, XPathConstants.NODE);
       if (nd==null) {
@@ -307,50 +308,51 @@
 
       version = config.getFloat("/schema/@version", 1.0f);
 
-      String expression = "/schema/types/fieldtype | /schema/types/fieldType";
-      NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
-
+      final IndexSchema schema = this;
+      AbstractPluginLoader<FieldType> loader = new AbstractPluginLoader<FieldType>( "[schema.xml] fieldType" ) {
 
-      for (int i=0; i<nodes.getLength(); i++) {
-        Node node = nodes.item(i);
-        NamedNodeMap attrs = node.getAttributes();
-
-        String name = DOMUtil.getAttr(attrs,"name","fieldtype error");
-        log.finest("reading fieldtype "+name);
-        String clsName = DOMUtil.getAttr(attrs,"class", "fieldtype error");
-        FieldType ft = (FieldType)Config.newInstance(clsName);
-        ft.setTypeName(name);
-
-        expression = "./analyzer[@type='query']";
-        Node anode = (Node)xpath.evaluate(expression, node, XPathConstants.NODE);
-        Analyzer queryAnalyzer = readAnalyzer(anode);
-
-        // An analyzer without a type specified, or with type="index"
-        expression = "./analyzer[not(@type)] | ./analyzer[@type='index']";
-        anode = (Node)xpath.evaluate(expression, node, XPathConstants.NODE);
-        Analyzer analyzer = readAnalyzer(anode);
-
-        if (queryAnalyzer==null) queryAnalyzer=analyzer;
-        if (analyzer==null) analyzer=queryAnalyzer;
-        if (analyzer!=null) {
-          ft.setAnalyzer(analyzer);
-          ft.setQueryAnalyzer(queryAnalyzer);
+        @Override
+        protected FieldType create( String name, String className, Map<String,String> params, Node node ) throws Exception
+        {
+          FieldType ft = (FieldType)Config.newInstance(className);
+          ft.setTypeName(name);
+
+          String expression = "./analyzer[@type='query']";
+          Node anode = (Node)xpath.evaluate(expression, node, XPathConstants.NODE);
+          Analyzer queryAnalyzer = readAnalyzer(anode);
+
+          // An analyzer without a type specified, or with type="index"
+          expression = "./analyzer[not(@type)] | ./analyzer[@type='index']";
+          anode = (Node)xpath.evaluate(expression, node, XPathConstants.NODE);
+          Analyzer analyzer = readAnalyzer(anode);
+
+          if (queryAnalyzer==null) queryAnalyzer=analyzer;
+          if (analyzer==null) analyzer=queryAnalyzer;
+          if (analyzer!=null) {
+            ft.setAnalyzer(analyzer);
+            ft.setQueryAnalyzer(queryAnalyzer);
+          }
+          return ft;
+        }
+        
+        @Override
+        protected void init(FieldType plugin, Map<String, String> params, Node node) throws Exception {
+          plugin.setArgs(schema, params );
         }
 
-
-        ft.setArgs(this, DOMUtil.toMapExcept(attrs,"name","class"));
-        FieldType old = fieldTypes.put(ft.typeName,ft);
-        if( old != null ) {
-          String msg = "[schema.xml] Duplicate fieldType definition for '"
-            + ft.typeName + "' ignoring: "+old.toString();
-          
-          Throwable t = new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
-          SolrException.logOnce(log,null,t);
-          SolrConfig.severeErrors.add( t );
+        @Override
+        protected FieldType register(String name, FieldType plugin) throws Exception {
+          log.finest("fieldtype defined: " + plugin );
+          return fieldTypes.put( name, plugin );
         }
-        log.finest("fieldtype defined: " + ft);
-      }
+      };
+      
+
+      String expression = "/schema/types/fieldtype | /schema/types/fieldType";
+      NodeList nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
+      loader.load( nodes );
 
+      
 
       // Hang on to the fields that say if they are required -- this lets us set a reasonable default for the unique key
       Map<String,Boolean> explicitRequiredProp = new HashMap<String, Boolean>();

Modified: lucene/solr/trunk/src/java/org/apache/solr/util/SolrPluginUtils.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/SolrPluginUtils.java?view=diff&rev=552680&r1=552679&r2=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/SolrPluginUtils.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/SolrPluginUtils.java Mon Jul  2 23:10:10 2007
@@ -17,7 +17,6 @@
 
 package org.apache.solr.util;
 
-import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.queryParser.ParseException;
 import org.apache.lucene.queryParser.QueryParser;
@@ -25,13 +24,13 @@
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.AppendedSolrParams;
-import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.DefaultSolrParams;
 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.core.SolrCore;
+import org.apache.solr.highlight.SolrHighlighter;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryResponse;
 import org.apache.solr.schema.IndexSchema;
@@ -39,7 +38,6 @@
 import org.apache.solr.search.*;
 
 import java.io.IOException;
-import java.io.StringReader;
 import java.util.*;
 import java.util.logging.Level;
 import java.util.regex.Pattern;
@@ -240,8 +238,9 @@
       // copy return fields list
       fieldFilter = new HashSet<String>(returnFields);
       // add highlight fields
-      if(HighlightingUtils.isHighlightingEnabled(req)) {
-        for(String field: HighlightingUtils.getHighlightFields(query, req, null)) 
+      SolrHighlighter highligher = req.getCore().getHighlighter();
+      if(highligher.isHighlightingEnabled(req.getParams())) {
+        for(String field: highligher.getHighlightFields(query, req, null)) 
           fieldFilter.add(field);        
       }
       // fetch unique key if one exists.
@@ -866,6 +865,8 @@
   }
 
 }
+
+
 
 
 

Added: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java?view=auto&rev=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java Mon Jul  2 23:10:10 2007
@@ -0,0 +1,177 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.plugin;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.DOMUtil;
+import org.apache.solr.core.Config;
+import org.apache.solr.core.SolrConfig;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * An abstract super class that manages standard solr-style plugin configuration.
+ * 
+ * @author ryan
+ * @version $Id$
+ * @since solr 1.3
+ */
+public abstract class AbstractPluginLoader<T>
+{
+  public static Logger log = Logger.getLogger(AbstractPluginLoader.class.getName());
+  
+  private final String type;
+  private final boolean preRegister;
+  
+  /**
+   * @param type is the 'type' name included in error messages.
+   * @param preRegister, if true, this will first register all Plugins, then it will initialize them.
+   */
+  public AbstractPluginLoader( String type, boolean preRegister )
+  {
+    this.type = type;
+    this.preRegister = preRegister;
+  }
+
+  public AbstractPluginLoader( String type )
+  {
+    this( type, false );
+  }
+  
+  /**
+   * Where to look for classes
+   */
+  protected String[] getDefaultPackages()
+  {
+    return new String[]{};
+  }
+  
+  /**
+   * @param name - The registered name
+   * @param className - class name for requested plugin
+   * @param params - the parameters specified in the XML
+   * @param node - the XML node defining this plugin
+   */
+  @SuppressWarnings("unchecked")
+  protected T create( String name, String className, Map<String,String> params, Node node ) throws Exception
+  {
+    return (T) Config.newInstance( className, getDefaultPackages() );
+  }
+  
+  /**
+   * Register a plugin with a given name.
+   * @return The plugin previously registered to this name, or null
+   */
+  abstract protected T register( String name, T plugin ) throws Exception;
+
+  /**
+   * Initialize the plugin
+   */
+  abstract protected void init( T plugin, Map<String,String> params, Node node ) throws Exception;
+
+  /**
+   * Given a NodeList from XML, this will
+   */
+  public T load( NodeList nodes )
+  {
+    List<PluginInitInfo> info = new ArrayList<PluginInitInfo>();
+    T defaultPlugin = null;
+    
+    if (nodes !=null ) {
+      for (int i=0; i<nodes.getLength(); i++) {
+        Node node = nodes.item(i);
+  
+        // In a production environment, we can tolerate an error in some request handlers, 
+        // still load the others, and have a working system.
+        try {
+          String name       = DOMUtil.getAttr(node,"name", type);
+          String className  = DOMUtil.getAttr(node,"class", type);
+          String defaultStr = DOMUtil.getAttr(node,"default", null );
+          
+          Map<String,String> params = DOMUtil.toMapExcept( node.getAttributes(), 
+              "name","class" );
+  
+          T plugin = create(name, className, params, node );
+          log.info("created "+name+": " + plugin.getClass().getName() );
+          
+          // Either initialize now or wait till everything has been registered
+          if( preRegister ) {
+            info.add( new PluginInitInfo( plugin, params, node ) );
+          }
+          else {
+            init( plugin, params, node );
+          }
+          
+          T old = register( name, plugin );
+          if( old != null ) {
+            throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, 
+                "Multiple "+type+" registered to the same name: "+name+" ignoring: "+old );
+          }
+          
+          if( defaultStr != null && Boolean.parseBoolean( defaultStr ) ) {
+            if( defaultPlugin != null ) {
+              throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, 
+                "Multiple default "+type+" plugins: "+defaultPlugin + " AND " + name );
+            }
+            defaultPlugin = plugin;
+          }
+        }
+        catch (Exception e) {
+          SolrConfig.severeErrors.add( e );
+          SolrException.logOnce(log,null,e);
+        }
+      }
+    }
+    
+    // If everything needs to be registered *first*, this will initialize later
+    for( PluginInitInfo pinfo : info ) {
+      try {
+        init( pinfo.plugin, pinfo.params, pinfo.node );
+      }
+      catch( Exception ex ) {
+        SolrConfig.severeErrors.add( ex );
+        SolrException.logOnce(log,null,ex);
+      }
+    }
+    return defaultPlugin;
+  }
+  
+
+  /**
+   * Internal class to hold onto initialization info so that it can be initialized 
+   * after it is registered.
+   */
+  private class PluginInitInfo
+  {
+    final T plugin;
+    final Map<String,String> params;
+    final Node node;
+    
+    PluginInitInfo( T plugin, Map<String,String> params, Node node )
+    {
+      this.plugin = plugin;
+      this.params = params;
+      this.node = node;
+    }
+  }
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/AbstractPluginLoader.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java?view=auto&rev=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java Mon Jul  2 23:10:10 2007
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.plugin;
+
+import java.util.Map;
+
+/**
+ * A plugin that can be initialized with a Map<String,String>
+ * 
+ * @author ryan
+ * @version $Id$
+ * @since solr 1.3
+ */
+public interface MapInitializedPlugin {
+  void init( Map<String,String> args );
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapInitializedPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java?view=auto&rev=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java Mon Jul  2 23:10:10 2007
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.plugin;
+
+import java.util.Map;
+
+import org.w3c.dom.Node;
+
+/**
+ * 
+ * @author ryan
+ * @version $Id$
+ * @since solr 1.3
+ */
+public class MapPluginLoader<T extends MapInitializedPlugin> extends AbstractPluginLoader<T> 
+{
+  private final Map<String,T> registry;
+  
+  public MapPluginLoader( String name, Map<String,T> map )
+  {
+    super( name );
+    registry = map;
+  }
+
+  @Override
+  protected void init(T plugin, Map<String, String> params, Node node) throws Exception {
+    plugin.init( params );
+  }
+
+  @Override
+  protected T register(String name, T plugin) throws Exception {
+    if( registry != null ) {
+      return registry.put( name, plugin );
+    }
+    return null;
+  }
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/MapPluginLoader.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java?view=auto&rev=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java Mon Jul  2 23:10:10 2007
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.plugin;
+
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * A plugin that can be initialized with a NamedList
+ * 
+ * @author ryan
+ * @version $Id$
+ * @since solr 1.3
+ */
+public interface NamedListInitializedPlugin {
+  void init( NamedList args );
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListInitializedPlugin.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java?view=auto&rev=552680
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java (added)
+++ lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java Mon Jul  2 23:10:10 2007
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.plugin;
+
+import java.util.Map;
+
+import org.apache.solr.common.util.DOMUtil;
+import org.w3c.dom.Node;
+
+/**
+ * @author ryan
+ * @version $Id$
+ * @since solr 1.3
+ */
+public class NamedListPluginLoader<T extends NamedListInitializedPlugin> extends AbstractPluginLoader<T> 
+{
+  private final Map<String,T> registry;
+  
+  public NamedListPluginLoader( String name, Map<String,T> map )
+  {
+    super( name );
+    registry = map;
+  }
+
+  @Override
+  protected void init(T plugin, Map<String, String> params, Node node) throws Exception {
+    plugin.init( DOMUtil.childNodesToNamedList(node) );
+  }
+
+  @Override
+  protected T register(String name, T plugin) throws Exception {
+    if( registry != null ) {
+      return registry.put( name, plugin );
+    }
+    return null;
+  }
+}

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/java/org/apache/solr/util/plugin/NamedListPluginLoader.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL