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.Date;
23   
24   import org.apache.lucene.index.IndexReader;
25   import org.apache.lucene.index.Term;
26   import org.apache.lucene.index.TermDocs;
27   import org.apache.lucene.index.TermEnum;
28   import org.apache.lucene.search.CachingWrapperFilter;
29   import org.apache.lucene.search.DocIdSet;
30   import org.apache.lucene.search.Filter;
31   import org.apache.lucene.util.DocIdBitSet;
32   import org.hibernate.search.annotations.Factory;
33   
34   /**
35    * a {@code Filter} removing {@code SitemapNode} which are not valid.
36    * 
37    * @see org.torweg.pulse.site.map.SitemapNode#getDuration()
38    * @author unknown, Thomas Weber
39    * @version $Revision: 1415 $
40    */
41   public class SitemapNodeDurationFilterFactory {
42   
43       /**
44        * default constructor.
45        */
46       public SitemapNodeDurationFilterFactory() {
47           super();
48       }
49   
50       /**
51        * factory method to create a cacheable version of
52        * {@code SitemapNodeUniqueContentFilter}.
53        * 
54        * @see Factory
55        * @return the cachable filter
56        */
57       @Factory
58       public final Filter getFilter() {
59           Filter filter = new SitemapNodeValidityFilter();
60           return new CachingWrapperFilter(filter);
61       }
62   
63       /**
64        * The filter checking whether the the documents are part of the given
65        * sections.
66        * 
67        * @author Thomas Weber
68        * @version $Revision: 1415 $
69        */
70       public static class SitemapNodeValidityFilter extends Filter {
71   
72           /**
73            * serialVersionUID.
74            */
75           private static final long serialVersionUID = -4168019388047484467L;
76   
77           /**
78            * creates a new filter for the given set of roles.
79            */
80           public SitemapNodeValidityFilter() {
81               super();
82           }
83   
84           /**
85            * does the actual filtering.
86            * 
87            * @param reader
88            *            the index reader
89            * @return a bit set with the results to be included
90            * @throws IOException
91            *             on errors accessing the index
92            * @see org.apache.lucene.search.Filter#getDocIdSet(org.apache.lucene.index.IndexReader)
93            */
94           @Override
95           public final DocIdSet getDocIdSet(final IndexReader reader)
96                   throws IOException {
97               // assume all documents are valid
98               Date now = new Date();
99               BitSet mask = new BitSet(reader.maxDoc());
100              mask.flip(0, reader.maxDoc());
101  
102              removeFutureStartDates(reader, now, mask);
103              removePastEndDates(reader, now, mask);
104  
105              return new DocIdBitSet(mask);
106          }
107  
108          /**
109           * removes results with future start dates.
110           * 
111           * @param reader
112           *            the index reader
113           * @param now
114           *            the current time
115           * @param mask
116           *            the bit mask
117           * @throws IOException
118           *             on errors accessing the index
119           */
120          private void removeFutureStartDates(final IndexReader reader,
121                  final Date now, final BitSet mask) throws IOException {
122              Term rolesTerm = new Term("validity_startDate", "");
123              // get all terms for "validity_startDate"
124              TermEnum termEnumeration = reader.terms(rolesTerm);
125              if (termEnumeration != null) {
126                  // check per term
127                  Term currentTerm = termEnumeration.term();
128                  while ((currentTerm != null)
129                          && (currentTerm.field().equals(rolesTerm.field()))) {
130  
131                      Date start = new Date(Long.parseLong(currentTerm.text()));
132                      // start date is after now
133                      if (start.getTime() > now.getTime()) {
134                          // get all docs with the current term
135                          TermDocs td = reader.termDocs(currentTerm);
136                          // and mark them as invalid
137                          while (td.next()) {
138                              mask.clear(td.doc());
139                          }
140                      }
141                      if (!termEnumeration.next()) {
142                          break;
143                      }
144                      // continue with the next term
145                      currentTerm = termEnumeration.term();
146                  }
147              }
148          }
149  
150          /**
151           * removes results with end dates in the past.
152           * 
153           * @param reader
154           *            the index reader
155           * @param now
156           *            the current time
157           * @param mask
158           *            the bit mask
159           * @throws IOException
160           *             on errors accessing the index
161           */
162          private void removePastEndDates(final IndexReader reader,
163                  final Date now, final BitSet mask) throws IOException {
164              Term rolesTerm = new Term("validity_endDate", "");
165              // get all terms for "validity_startDate"
166              TermEnum termEnumeration = reader.terms(rolesTerm);
167              if (termEnumeration != null) {
168                  // check per term
169                  Term currentTerm = termEnumeration.term();
170                  while ((currentTerm != null)
171                          && (currentTerm.field().equals(rolesTerm.field()))) {
172  
173                      Date end = new Date(Long.parseLong(currentTerm.text()));
174                      // end date is in the past
175                      if (end.getTime() < now.getTime()) {
176                          // get all docs with the current term
177                          TermDocs td = reader.termDocs(currentTerm);
178                          // and mark them as invalid
179                          while (td.next()) {
180                              mask.clear(td.doc());
181                          }
182                      }
183                      if (!termEnumeration.next()) {
184                          break;
185                      }
186                      // continue with the next term
187                      currentTerm = termEnumeration.term();
188                  }
189              }
190          }
191      }
192  }
193