content: /**
   * 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.lucene.analysis;
  
  import java.io.IOException;
  import java.io.Reader;
  
  /**
   * An convenience subclass of Analyzer that makes it easy to implement
   * {@link TokenStream} reuse.
   * <p>
   * ReusableAnalyzerBase is a simplification of Analyzer that supports easy reuse
   * for the most common use-cases. Analyzers such as
   * {@link PerFieldAnalyzerWrapper} that behave differently depending upon the
   * field name need to subclass Analyzer directly instead.
   * </p>
   * <p>
   * To prevent consistency problems, this class does not allow subclasses to
   * extend {@link #reusableTokenStream(String, Reader)} or
   * {@link #tokenStream(String, Reader)} directly. Instead, subclasses must
   * implement {@link #createComponents(String, Reader)}.
   * </p>
   */
  public abstract class ReusableAnalyzerBase extends Analyzer {
  
    /**
     * Creates a new {@link TokenStreamComponents} instance for this analyzer.
     * 
     * @param fieldName
     *          the name of the fields content passed to the
     *          {@link TokenStreamComponents} sink as a reader
     * @param aReader
     *          the reader passed to the {@link Tokenizer} constructor
     * @return the {@link TokenStreamComponents} for this analyzer.
     */
    protected abstract TokenStreamComponents createComponents(String fieldName,
        Reader aReader);
  
    /**
     * This method uses {@link #createComponents(String, Reader)} to obtain an
     * instance of {@link TokenStreamComponents}. It returns the sink of the
     * components and stores the components internally. Subsequent calls to this
     * method will reuse the previously stored components if and only if the
     * {@link TokenStreamComponents#reset(Reader)} method returned
     * <code>true</code>. Otherwise a new instance of
     * {@link TokenStreamComponents} is created.
     * 
     * @param fieldName the name of the field the created TokenStream is used for
     * @param reader the reader the streams source reads from
     */
    @Override
    public final TokenStream reusableTokenStream(final String fieldName,
        final Reader reader) throws IOException {
      TokenStreamComponents streamChain = (TokenStreamComponents)
      getPreviousTokenStream();
      final Reader r = initReader(reader);
      if (streamChain == null || !streamChain.reset(r)) {
        streamChain = createComponents(fieldName, r);
        setPreviousTokenStream(streamChain);
      }
      return streamChain.getTokenStream();
    }
  
    /**
     * This method uses {@link #createComponents(String, Reader)} to obtain an
     * instance of {@link TokenStreamComponents} and returns the sink of the
     * components. Each calls to this method will create a new instance of
     * {@link TokenStreamComponents}. Created {@link TokenStream} instances are 
     * never reused.
     * 
     * @param fieldName the name of the field the created TokenStream is used for
     * @param reader the reader the streams source reads from
     */
    @Override
    public final TokenStream tokenStream(final String fieldName,
        final Reader reader) {
      return createComponents(fieldName, initReader(reader)).getTokenStream();
    }
    
    /**
     * Override this if you want to add a CharFilter chain.
     */
    protected Reader initReader(Reader reader) {
      return reader;
    }
    
    /**
     * This class encapsulates the outer components of a token stream. It provides
     * access to the source ({@link Tokenizer}) and the outer end (sink), an
     * instance of {@link TokenFilter} which also serves as the
     * {@link TokenStream} returned by
     * {@link Analyzer#tokenStream(String, Reader)} and
     * {@link Analyzer#reusableTokenStream(String, Reader)}.
     */
    public static class TokenStreamComponents {
      protected final Tokenizer source;
      protected final TokenStream sink;
  
      /**
       * Creates a new {@link TokenStreamComponents} instance.
       * 
       * @param source
       *          the analyzer's tokenizer
       * @param result
       *          the analyzer's resulting token stream
       */
      public TokenStreamComponents(final Tokenizer source,
          final TokenStream result) {
        this.source = source;
        this.sink = result;
      }
      
      /**
       * Creates a new {@link TokenStreamComponents} instance.
       * 
       * @param source
       *          the analyzer's tokenizer
       */
      public TokenStreamComponents(final Tokenizer source) {
        this.source = source;
        this.sink = source;
      }
  
      /**
       * Resets the encapsulated components with the given reader. This method by
       * default returns <code>true</code> indicating that the components have
       * been reset successfully. Subclasses of {@link ReusableAnalyzerBase} might use
       * their own {@link TokenStreamComponents} returning <code>false</code> if
       * the components cannot be reset.
       * 
       * @param reader
       *          a reader to reset the source component
       * @return <code>true</code> if the components were reset, otherwise
       *         <code>false</code>
       * @throws IOException
       *           if the component's reset method throws an {@link IOException}
       */
      protected boolean reset(final Reader reader) throws IOException {
        source.reset(reader);
        return true;
      }
  
      /**
       * Returns the sink {@link TokenStream}
       * 
       * @return the sink {@link TokenStream}
       */
      protected TokenStream getTokenStream() {
        return sink;
      }
  
    }
  
  }
  