### Eclipse Workspace Patch 1.0
#P stopword_patch
Index: src/java/org/apache/lucene/analysis/StopFilter.java
===================================================================
--- src/java/org/apache/lucene/analysis/StopFilter.java	(revision 784765)
+++ src/java/org/apache/lucene/analysis/StopFilter.java	(working copy)
@@ -55,6 +55,7 @@
    * @param enablePositionIncrements true if token positions should record the removed stop words
    * @param input input TokenStream
    * @param stopWords array of stop words
+   * @deprecated Use {@link #StopFilter(boolean, TokenStream, Set)} instead.
    */
   public StopFilter(boolean enablePositionIncrements, TokenStream input, String [] stopWords)
   {
@@ -77,6 +78,7 @@
    * @param in input TokenStream
    * @param stopWords array of stop words
    * @param ignoreCase true if case is ignored
+   * @deprecated Use {@link #StopFilter(boolean, TokenStream, Set, boolean)} instead.
    */
   public StopFilter(boolean enablePositionIncrements, TokenStream in, String[] stopWords, boolean ignoreCase) {
     super(in);
Index: src/java/org/apache/lucene/analysis/StopAnalyzer.java
===================================================================
--- src/java/org/apache/lucene/analysis/StopAnalyzer.java	(revision 784765)
+++ src/java/org/apache/lucene/analysis/StopAnalyzer.java	(working copy)
@@ -20,18 +20,20 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.Reader;
+import java.util.Arrays;
 import java.util.Set;
 
 /** Filters LetterTokenizer with LowerCaseFilter and StopFilter. */
 
 public final class StopAnalyzer extends Analyzer {
-  private Set stopWords;
+  private final Set/*<String>*/ stopWords;
   // @deprecated
-  private boolean useDefaultStopPositionIncrement;
-  private boolean enablePositionIncrements;
+  private final boolean useDefaultStopPositionIncrement;
+  private final boolean enablePositionIncrements;
 
   /** An array containing some common English words that are not usually useful
-    for searching. */
+    for searching. 
+    @deprecated Use {@link #ENGLISH_STOP_WORDS_SET} instead */
   public static final String[] ENGLISH_STOP_WORDS = {
     "a", "an", "and", "are", "as", "at", "be", "but", "by",
     "for", "if", "in", "into", "is", "it",
@@ -39,13 +41,31 @@
     "that", "the", "their", "then", "there", "these",
     "they", "this", "to", "was", "will", "with"
   };
-
+  
+  /** An unmodifiable set containing some common English words that are not usually useful
+  for searching.*/
+  public static final Set/*<String>*/ ENGLISH_STOP_WORDS_SET;
+  
+  static {
+	  final String[] stopWords = new String[]{
+  	    "a", "an", "and", "are", "as", "at", "be", "but", "by",
+	    "for", "if", "in", "into", "is", "it",
+	    "no", "not", "of", "on", "or", "such",
+	    "that", "the", "their", "then", "there", "these",
+	    "they", "this", "to", "was", "will", "with"
+	  };
+	  final CharArraySet stopSet = new CharArraySet(stopWords.length, false);
+    stopSet.addAll(Arrays.asList(stopWords));  
+	  ENGLISH_STOP_WORDS_SET = CharArraySet.unmodifiableSet(stopSet); 
+  }
+  
   /** Builds an analyzer which removes words in
    * ENGLISH_STOP_WORDS.
    * @deprecated Use {@link #StopAnalyzer(boolean)} instead */
   public StopAnalyzer() {
-    stopWords = StopFilter.makeStopSet(ENGLISH_STOP_WORDS);
+    stopWords = ENGLISH_STOP_WORDS_SET;
     useDefaultStopPositionIncrement = true;
+    enablePositionIncrements = false;
   }
 
   /** Builds an analyzer which removes words in
@@ -53,8 +73,9 @@
    * @param enablePositionIncrements See {@link
    * StopFilter#setEnablePositionIncrements} */
   public StopAnalyzer(boolean enablePositionIncrements) {
-    stopWords = StopFilter.makeStopSet(ENGLISH_STOP_WORDS);
+    stopWords = ENGLISH_STOP_WORDS_SET;
     this.enablePositionIncrements = enablePositionIncrements;
+    useDefaultStopPositionIncrement = false;
   }
 
   /** Builds an analyzer with the stop words from the given set.
@@ -62,6 +83,7 @@
   public StopAnalyzer(Set stopWords) {
     this.stopWords = stopWords;
     useDefaultStopPositionIncrement = true;
+    enablePositionIncrements = false;
   }
 
   /** Builds an analyzer with the stop words from the given set.
@@ -71,22 +93,26 @@
   public StopAnalyzer(Set stopWords, boolean enablePositionIncrements) {
     this.stopWords = stopWords;
     this.enablePositionIncrements = enablePositionIncrements;
+    useDefaultStopPositionIncrement = false;
   }
 
   /** Builds an analyzer which removes words in the provided array.
-   * @deprecated Use {@link #StopAnalyzer(String[], boolean)} instead */
+   * @deprecated Use {@link #StopAnalyzer(Set, boolean)} instead */
   public StopAnalyzer(String[] stopWords) {
     this.stopWords = StopFilter.makeStopSet(stopWords);
     useDefaultStopPositionIncrement = true;
+    enablePositionIncrements = false;
   }
   
   /** Builds an analyzer which removes words in the provided array.
    * @param stopWords Array of stop words
    * @param enablePositionIncrements See {@link
-   * StopFilter#setEnablePositionIncrements} */
+   * StopFilter#setEnablePositionIncrements} 
+   * @deprecated Use {@link #StopAnalyzer(Set, boolean) instead*/
   public StopAnalyzer(String[] stopWords, boolean enablePositionIncrements) {
     this.stopWords = StopFilter.makeStopSet(stopWords);
     this.enablePositionIncrements = enablePositionIncrements;
+    useDefaultStopPositionIncrement = false;
   }
   
   /** Builds an analyzer with the stop words from the given file.
@@ -95,6 +121,7 @@
   public StopAnalyzer(File stopwordsFile) throws IOException {
     stopWords = WordlistLoader.getWordSet(stopwordsFile);
     useDefaultStopPositionIncrement = true;
+    enablePositionIncrements = false;
   }
 
   /** Builds an analyzer with the stop words from the given file.
@@ -105,6 +132,7 @@
   public StopAnalyzer(File stopwordsFile, boolean enablePositionIncrements) throws IOException {
     stopWords = WordlistLoader.getWordSet(stopwordsFile);
     this.enablePositionIncrements = enablePositionIncrements;
+    useDefaultStopPositionIncrement = false;
   }
 
   /** Builds an analyzer with the stop words from the given reader.
@@ -114,6 +142,7 @@
   public StopAnalyzer(Reader stopwords) throws IOException {
     stopWords = WordlistLoader.getWordSet(stopwords);
     useDefaultStopPositionIncrement = true;
+    enablePositionIncrements = false;
   }
 
   /** Builds an analyzer with the stop words from the given reader.
@@ -124,6 +153,7 @@
   public StopAnalyzer(Reader stopwords, boolean enablePositionIncrements) throws IOException {
     stopWords = WordlistLoader.getWordSet(stopwords);
     this.enablePositionIncrements = enablePositionIncrements;
+    useDefaultStopPositionIncrement = false;
   }
 
   /** Filters LowerCaseTokenizer with StopFilter. */
Index: src/java/org/apache/lucene/analysis/standard/StandardAnalyzer.java
===================================================================
--- src/java/org/apache/lucene/analysis/standard/StandardAnalyzer.java	(revision 784765)
+++ src/java/org/apache/lucene/analysis/standard/StandardAnalyzer.java	(working copy)
@@ -89,15 +89,21 @@
 
 
   /** An array containing some common English words that are usually not
+  useful for searching. 
+  @deprecated Use {@link #STOP_WORDS_SET} instead 
+  */
+  public static final String[] STOP_WORDS = StopAnalyzer.ENGLISH_STOP_WORDS;
+  
+  /** An unmodifiable set containing some common English words that are usually not
   useful for searching. */
-  public static final String[] STOP_WORDS = StopAnalyzer.ENGLISH_STOP_WORDS;
+  public static final Set/*<String>*/ STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET; 
 
   /** Builds an analyzer with the default stop words ({@link
-   * #STOP_WORDS}).
-   * @deprecated Use {@link #StandardAnalyzer(boolean, String[])},
+   * #STOP_WORDS_SET}).
+   * @deprecated Use {@link #StandardAnalyzer(boolean, Set)},
    * passing in null for the stop words, instead */
   public StandardAnalyzer() {
-    this(STOP_WORDS);
+    this(STOP_WORDS_SET);
   }
 
   /** Builds an analyzer with the given stop words.
@@ -119,19 +125,21 @@
 
   /** Builds an analyzer with the given stop words.
    * @deprecated Use {@link #StandardAnalyzer(boolean,
-   * String[])} instead */
+   * Set)} instead */
   public StandardAnalyzer(String[] stopWords) {
     if (stopWords == null) {
-      stopWords = STOP_WORDS;
+      stopSet = STOP_WORDS_SET;
+    } else {
+      stopSet = StopFilter.makeStopSet(stopWords);
     }
-    stopSet = StopFilter.makeStopSet(stopWords);
     useDefaultStopPositionIncrements = true;
   }
 
   /** Builds an analyzer with the given stop words.
    * @param enableStopPositionIncrements See {@link
    * StopFilter#setEnablePositionIncrements}
-   * @param stopWords Array of stop words */
+   * @param stopWords Array of stop words 
+   * @deprecated Use {@link #StandardAnalyzer(boolean, Set)} instead.*/
   public StandardAnalyzer(boolean enableStopPositionIncrements, String[] stopWords) {
     stopSet = StopFilter.makeStopSet(stopWords);
     this.enableStopPositionIncrements = enableStopPositionIncrements;
@@ -186,7 +194,7 @@
    * @deprecated Remove in 3.X and make true the only valid value
    */
   public StandardAnalyzer(boolean replaceInvalidAcronym) {
-    this(STOP_WORDS);
+    this(STOP_WORDS_SET);
     this.replaceInvalidAcronym = replaceInvalidAcronym;
     useDefaultStopPositionIncrements = true;
   }
Index: src/java/org/apache/lucene/analysis/CharArraySet.java
===================================================================
--- src/java/org/apache/lucene/analysis/CharArraySet.java	(revision 784765)
+++ src/java/org/apache/lucene/analysis/CharArraySet.java	(working copy)
@@ -2,6 +2,7 @@
 
 import java.util.AbstractSet;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 
 /**
@@ -53,6 +54,12 @@
     this(c.size(), ignoreCase);
     addAll(c);
   }
+  /** Create set from entries */
+  private CharArraySet(char[][] entries, boolean ignoreCase, int count){
+    this.entries = entries;
+    this.ignoreCase = ignoreCase;
+    this.count = count;
+  }
 
   /** true if the <code>len</code> chars of <code>text</code> starting at <code>off</code>
    * are in the set */
@@ -100,7 +107,7 @@
   public boolean add(CharSequence text) {
     return add(text.toString()); // could be more efficient
   }
-
+  
   /** Add this String into the set */
   public boolean add(String text) {
     return add(text.toCharArray());
@@ -228,6 +235,26 @@
     }
     return add(o.toString());
   }
+  
+  /**
+   * Returns an unmodifiable {@link CharArraySet}. This allows to provide
+   * unmodifiable views of internal sets for "read-only" use.
+   * 
+   * @param set
+   *          a set for which the unmodifiable set is returned.
+   * @return an new unmodifiable {@link CharArraySet}.
+   * @throws NullPointerException
+   *           if the given set is <code>null</code>.
+   */
+  public static CharArraySet unmodifiableSet(CharArraySet set) {
+    if (set == null)
+      throw new NullPointerException("Given set is null");
+    /*
+     * Instead of delegating calls to the given set copy the low-level values to
+     * the unmodifiable Subclass
+     */
+    return new UnmodifiableCharArraySet(set.entries, set.ignoreCase, set.count);
+  }
 
   /** The Iterator<String> for this set.  Strings are constructed on the fly, so
    * use <code>nextCharArray</code> for more efficient access. */
@@ -270,5 +297,40 @@
   public Iterator iterator() {
     return new CharArraySetIterator();
   }
+  
+  /**
+   * Efficient unmodifiable {@link CharArraySet}. This implementation does not
+   * delegate calls to a give {@link CharArraySet} like
+   * {@link Collections#unmodifiableSet(java.util.Set)} does. Instead is passes
+   * the internal representation of a {@link CharArraySet} to a super
+   * constructor and overrides all mutators. 
+   */
+  private static final class UnmodifiableCharArraySet extends CharArraySet {
 
+    private UnmodifiableCharArraySet(char[][] entries, boolean ignoreCase,
+        int count) {
+      super(entries, ignoreCase, count);
+    }
+
+    public boolean add(Object o){
+      throw new UnsupportedOperationException();
+    }
+    
+    public boolean addAll(Collection coll) {
+      throw new UnsupportedOperationException();
+    }
+    
+    public boolean add(char[] text) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean add(CharSequence text) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean add(String text) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
 }
Index: src/test/org/apache/lucene/analysis/TestCharArraySet.java
===================================================================
--- src/test/org/apache/lucene/analysis/TestCharArraySet.java	(revision 784765)
+++ src/test/org/apache/lucene/analysis/TestCharArraySet.java	(working copy)
@@ -23,13 +23,22 @@
 
 public class TestCharArraySet extends LuceneTestCase {
   
+  static final String[] TEST_STOP_WORDS = {
+    "a", "an", "and", "are", "as", "at", "be", "but", "by",
+    "for", "if", "in", "into", "is", "it",
+    "no", "not", "of", "on", "or", "such",
+    "that", "the", "their", "then", "there", "these",
+    "they", "this", "to", "was", "will", "with"
+  };
+  
+  
   public void testRehash() throws Exception {
     CharArraySet cas = new CharArraySet(0, true);
-    for(int i=0;i<StopAnalyzer.ENGLISH_STOP_WORDS.length;i++)
-      cas.add(StopAnalyzer.ENGLISH_STOP_WORDS[i]);
-    assertEquals(StopAnalyzer.ENGLISH_STOP_WORDS.length, cas.size());
-    for(int i=0;i<StopAnalyzer.ENGLISH_STOP_WORDS.length;i++)
-      assertTrue(cas.contains(StopAnalyzer.ENGLISH_STOP_WORDS[i]));
+    for(int i=0;i<TEST_STOP_WORDS.length;i++)
+      cas.add(TEST_STOP_WORDS[i]);
+    assertEquals(TEST_STOP_WORDS.length, cas.size());
+    for(int i=0;i<TEST_STOP_WORDS.length;i++)
+      assertTrue(cas.contains(TEST_STOP_WORDS[i]));
   }
 
   public void testNonZeroOffset() {
@@ -39,6 +48,11 @@
     set.addAll(Arrays.asList(words));
     assertTrue(set.contains(findme, 1, 4));
     assertTrue(set.contains(new String(findme,1,4)));
+    
+    // test unmodifiable
+    set = CharArraySet.unmodifiableSet(set);
+    assertTrue(set.contains(findme, 1, 4));
+    assertTrue(set.contains(new String(findme,1,4)));
   }
   
   public void testObjectContains() {
@@ -47,5 +61,118 @@
     set.add(val);
     assertTrue(set.contains(val));
     assertTrue(set.contains(new Integer(1)));
+    // test unmodifiable
+    set = CharArraySet.unmodifiableSet(set);
+    assertTrue(set.contains(val));
+    assertTrue(set.contains(new Integer(1)));
   }
+  
+  public void testClear(){
+    CharArraySet set=new CharArraySet(10,true);
+    set.addAll(Arrays.asList(TEST_STOP_WORDS));
+    assertEquals("Not all words added", TEST_STOP_WORDS.length, set.size());
+    try{
+      set.clear();
+      fail("remove is not supported");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertEquals("Not all words added", TEST_STOP_WORDS.length, set.size());
+    }
+  }
+  
+  public void testModifyOnUnmodifiable(){
+    CharArraySet set=new CharArraySet(10,true);
+    set.addAll(Arrays.asList(TEST_STOP_WORDS));
+    final int size = set.size();
+    set = CharArraySet.unmodifiableSet(set);
+    assertEquals("Set size changed due to unmodifiableSet call" , size, set.size());
+    String NOT_IN_SET = "SirGallahad";
+    assertFalse("Test String already exists in set", set.contains(NOT_IN_SET));
+    
+    try{
+      set.add(NOT_IN_SET.toCharArray());  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertFalse("Test String has been added to unmodifiable set", set.contains(NOT_IN_SET));
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    
+    try{
+      set.add(NOT_IN_SET);  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertFalse("Test String has been added to unmodifiable set", set.contains(NOT_IN_SET));
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    
+    try{
+      set.add(new StringBuffer(NOT_IN_SET));  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertFalse("Test String has been added to unmodifiable set", set.contains(NOT_IN_SET));
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    
+    try{
+      set.clear();  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertFalse("Changed unmodifiable set", set.contains(NOT_IN_SET));
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    try{
+      set.add((Object) NOT_IN_SET);  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertFalse("Test String has been added to unmodifiable set", set.contains(NOT_IN_SET));
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    try{
+      set.removeAll(Arrays.asList(TEST_STOP_WORDS));  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    
+    try{
+      set.retainAll(Arrays.asList(new String[]{NOT_IN_SET}));  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertEquals("Size of unmodifiable set has changed", size, set.size());
+    }
+    
+    try{
+      set.addAll(Arrays.asList(new String[]{NOT_IN_SET}));  
+      fail("Modified unmodifiable set");
+    }catch (UnsupportedOperationException e) {
+      // expected
+      assertFalse("Test String has been added to unmodifiable set", set.contains(NOT_IN_SET));
+    }
+    
+    for (int i = 0; i < TEST_STOP_WORDS.length; i++) {
+      assertTrue(set.contains(TEST_STOP_WORDS[i]));  
+    }
+  }
+  
+  public void testUnmodifiableSet(){
+    CharArraySet set=new CharArraySet(10,true);
+    set.addAll(Arrays.asList(TEST_STOP_WORDS));
+    final int size = set.size();
+    set = CharArraySet.unmodifiableSet(set);
+    assertEquals("Set size changed due to unmodifiableSet call" , size, set.size());
+    
+    try{
+      CharArraySet.unmodifiableSet(null);
+      fail("can not make null unmodifiable");
+    }catch (NullPointerException e) {
+      // expected
+    }
+  }
 }
Index: contrib/analyzers/src/java/org/apache/lucene/analysis/th/ThaiAnalyzer.java
===================================================================
--- contrib/analyzers/src/java/org/apache/lucene/analysis/th/ThaiAnalyzer.java	(revision 784765)
+++ contrib/analyzers/src/java/org/apache/lucene/analysis/th/ThaiAnalyzer.java	(working copy)
@@ -33,7 +33,7 @@
 	  TokenStream ts = new StandardTokenizer(reader);
     ts = new StandardFilter(ts);
     ts = new ThaiWordFilter(ts);
-    ts = new StopFilter(ts, StopAnalyzer.ENGLISH_STOP_WORDS);
+    ts = new StopFilter(ts, StopAnalyzer.ENGLISH_STOP_WORDS_SET);
     return ts;
   }
 }
