1    /*
2     * Copyright 2008 :torweg free software group
3     * 
4     * This program is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     * 
9     * This program is distributed in the hope that it will be useful,
10    * but WITHOUT ANY WARRANTY; without even the implied warranty of
11    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    * GNU General Public License for more details.
13    * 
14    * You should have received a copy of the GNU General Public License
15    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16    *
17    */
18   package org.torweg.pulse.util.search;
19   
20   import java.io.IOException;
21   import java.util.BitSet;
22   import java.util.Collection;
23   import java.util.HashSet;
24   import java.util.Set;
25   
26   import org.apache.lucene.index.IndexReader;
27   import org.apache.lucene.index.Term;
28   import org.apache.lucene.index.TermDocs;
29   import org.apache.lucene.index.TermEnum;
30   import org.apache.lucene.search.CachingWrapperFilter;
31   import org.apache.lucene.search.DocIdSet;
32   import org.apache.lucene.search.Filter;
33   import org.apache.lucene.util.DocIdBitSet;
34   import org.hibernate.search.annotations.Factory;
35   import org.hibernate.search.annotations.Key;
36   import org.hibernate.search.filter.FilterKey;
37   import org.hibernate.search.filter.StandardFilterKey;
38   
39   /**
40    * a {@code Filter} restricting the search to the given sections.
41    * 
42    * @see org.torweg.pulse.site.map.SitemapNode
43    * @see org.torweg.pulse.site.map.SitemapSectionTag
44    * @author unknown, Thomas Weber
45    * @version $Revision: 1415 $
46    */
47   public class SitemapNodeSectionTagFilterFactory {
48   
49       /**
50        * the roles to check against.
51        */
52       private final Set<String> sections = new HashSet<String>();
53   
54       /**
55        * injects the section ids as strings.
56        * 
57        * @param r
58        *            the section ids
59        */
60       public final void setSections(final Collection<String> r) {
61           this.sections.clear();
62           this.sections.addAll(r);
63       }
64   
65       /**
66        * returns the {@code FilterKey}.
67        * 
68        * @return the filter key
69        */
70       @Key
71       public final FilterKey getKey() {
72           StandardFilterKey key = new StandardFilterKey();
73           key.addParameter(this.sections);
74           return key;
75       }
76   
77       /**
78        * default constructor.
79        */
80       public SitemapNodeSectionTagFilterFactory() {
81           super();
82       }
83   
84       /**
85        * factory method to create a cacheable version of
86        * {@code SitemapNodeUniqueContentFilter}.
87        * 
88        * @see Factory
89        * @return the cachable filter
90        */
91       @Factory
92       public final Filter getFilter() {
93           Filter filter = new SitemapNodeSectionTagFilter(this.sections);
94           return new CachingWrapperFilter(filter);
95       }
96   
97       /**
98        * The filter checking whether the the documents are part of the given
99        * sections.
100       * 
101       * @author Thomas Weber
102       * @version $Revision: 1415 $
103       */
104      public static class SitemapNodeSectionTagFilter extends Filter {
105  
106          /**
107           * serialVersionUID.
108           */
109          private static final long serialVersionUID = -4168019388047484467L;
110  
111          /**
112           * the set of section ids to check against.
113           */
114          private final Set<String> sectionIdSet;
115  
116          /**
117           * creates a new filter for the given set of roles.
118           * 
119           * @param sections
120           *            the section ids as strings
121           */
122          public SitemapNodeSectionTagFilter(final Set<String> sections) {
123              super();
124              this.sectionIdSet = sections;
125          }
126  
127          /**
128           * does the actual filtering.
129           * 
130           * @param reader
131           *            the index reader
132           * @return a bit set with the results to be included
133           * @throws IOException
134           *             on errors accessing the index
135           * @see org.apache.lucene.search.Filter#getDocIdSet(org.apache.lucene.index.IndexReader)
136           */
137          @Override
138          public final DocIdSet getDocIdSet(final IndexReader reader)
139                  throws IOException {
140              // assume all documents are invalid
141              BitSet roleMask = new BitSet(reader.maxDoc());
142  
143              Term rolesTerm = new Term("sectionTag.id", "");
144              // get all terms for "sectionTag.id"
145              TermEnum termEnumeration = reader.terms(rolesTerm);
146              if (termEnumeration != null) {
147                  // check per term
148                  Term currentTerm = termEnumeration.term();
149                  while ((currentTerm != null)
150                          && (currentTerm.field().equals(rolesTerm.field()))) {
151  
152                      // is term an id that is part if the requested ids
153                      if (this.sectionIdSet.contains(currentTerm.text())) {
154  
155                          // get all docs with the current term
156                          TermDocs td = reader.termDocs(currentTerm);
157                          // and mark them as valid
158                          while (td.next()) {
159                              roleMask.set(td.doc());
160                          }
161                      }
162                      if (!termEnumeration.next()) {
163                          break;
164                      }
165  
166                      // continue with the next term
167                      currentTerm = termEnumeration.term();
168                  }
169              }
170  
171              return new DocIdBitSet(roleMask);
172          }
173      }
174  }
175