pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / analyzers / common / src / java / org / apache / lucene / analysis / miscellaneous / PrefixAwareTokenFilter.java
1 package org.apache.lucene.analysis.miscellaneous;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import org.apache.lucene.analysis.Token;
21 import org.apache.lucene.analysis.TokenStream;
22 import org.apache.lucene.analysis.tokenattributes.FlagsAttribute;
23 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
24 import org.apache.lucene.analysis.tokenattributes.PayloadAttribute;
25 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
26 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
27 import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
28 import org.apache.lucene.index.Payload;
29
30 import java.io.IOException;
31
32
33 /**
34  * Joins two token streams and leaves the last token of the first stream available
35  * to be used when updating the token values in the second stream based on that token.
36  *
37  * The default implementation adds last prefix token end offset to the suffix token start and end offsets.
38  * <p/>
39  * <b>NOTE:</b> This filter might not behave correctly if used with custom Attributes, i.e. Attributes other than
40  * the ones located in org.apache.lucene.analysis.tokenattributes. 
41  */
42 public class PrefixAwareTokenFilter extends TokenStream {
43
44   private TokenStream prefix;
45   private TokenStream suffix;
46   
47   private CharTermAttribute termAtt;
48   private PositionIncrementAttribute posIncrAtt;
49   private PayloadAttribute payloadAtt;
50   private OffsetAttribute offsetAtt;
51   private TypeAttribute typeAtt;
52   private FlagsAttribute flagsAtt;
53
54   private CharTermAttribute p_termAtt;
55   private PositionIncrementAttribute p_posIncrAtt;
56   private PayloadAttribute p_payloadAtt;
57   private OffsetAttribute p_offsetAtt;
58   private TypeAttribute p_typeAtt;
59   private FlagsAttribute p_flagsAtt;
60
61   public PrefixAwareTokenFilter(TokenStream prefix, TokenStream suffix) {
62     super(suffix);
63     this.suffix = suffix;
64     this.prefix = prefix;
65     prefixExhausted = false;
66     
67     termAtt = addAttribute(CharTermAttribute.class);
68     posIncrAtt = addAttribute(PositionIncrementAttribute.class);
69     payloadAtt = addAttribute(PayloadAttribute.class);
70     offsetAtt = addAttribute(OffsetAttribute.class);
71     typeAtt = addAttribute(TypeAttribute.class);
72     flagsAtt = addAttribute(FlagsAttribute.class);
73
74     p_termAtt = prefix.addAttribute(CharTermAttribute.class);
75     p_posIncrAtt = prefix.addAttribute(PositionIncrementAttribute.class);
76     p_payloadAtt = prefix.addAttribute(PayloadAttribute.class);
77     p_offsetAtt = prefix.addAttribute(OffsetAttribute.class);
78     p_typeAtt = prefix.addAttribute(TypeAttribute.class);
79     p_flagsAtt = prefix.addAttribute(FlagsAttribute.class);
80   }
81
82   private Token previousPrefixToken = new Token();
83   private Token reusableToken = new Token();
84
85   private boolean prefixExhausted;
86
87   @Override
88   public final boolean incrementToken() throws IOException {
89     if (!prefixExhausted) {
90       Token nextToken = getNextPrefixInputToken(reusableToken);
91       if (nextToken == null) {
92         prefixExhausted = true;
93       } else {
94         previousPrefixToken.reinit(nextToken);
95         // Make it a deep copy
96         Payload p = previousPrefixToken.getPayload();
97         if (p != null) {
98           previousPrefixToken.setPayload((Payload) p.clone());
99         }
100         setCurrentToken(nextToken);
101         return true;
102       }
103     }
104
105     Token nextToken = getNextSuffixInputToken(reusableToken);
106     if (nextToken == null) {
107       return false;
108     }
109
110     nextToken = updateSuffixToken(nextToken, previousPrefixToken);
111     setCurrentToken(nextToken);
112     return true;
113   }
114   
115   private void setCurrentToken(Token token) {
116     if (token == null) return;
117     clearAttributes();
118     termAtt.copyBuffer(token.buffer(), 0, token.length());
119     posIncrAtt.setPositionIncrement(token.getPositionIncrement());
120     flagsAtt.setFlags(token.getFlags());
121     offsetAtt.setOffset(token.startOffset(), token.endOffset());
122     typeAtt.setType(token.type());
123     payloadAtt.setPayload(token.getPayload());
124   }
125   
126   private Token getNextPrefixInputToken(Token token) throws IOException {
127     if (!prefix.incrementToken()) return null;
128     token.copyBuffer(p_termAtt.buffer(), 0, p_termAtt.length());
129     token.setPositionIncrement(p_posIncrAtt.getPositionIncrement());
130     token.setFlags(p_flagsAtt.getFlags());
131     token.setOffset(p_offsetAtt.startOffset(), p_offsetAtt.endOffset());
132     token.setType(p_typeAtt.type());
133     token.setPayload(p_payloadAtt.getPayload());
134     return token;
135   }
136
137   private Token getNextSuffixInputToken(Token token) throws IOException {
138     if (!suffix.incrementToken()) return null;
139     token.copyBuffer(termAtt.buffer(), 0, termAtt.length());
140     token.setPositionIncrement(posIncrAtt.getPositionIncrement());
141     token.setFlags(flagsAtt.getFlags());
142     token.setOffset(offsetAtt.startOffset(), offsetAtt.endOffset());
143     token.setType(typeAtt.type());
144     token.setPayload(payloadAtt.getPayload());
145     return token;
146   }
147
148   /**
149    * The default implementation adds last prefix token end offset to the suffix token start and end offsets.
150    *
151    * @param suffixToken a token from the suffix stream
152    * @param lastPrefixToken the last token from the prefix stream
153    * @return consumer token
154    */
155   public Token updateSuffixToken(Token suffixToken, Token lastPrefixToken) {
156     suffixToken.setStartOffset(lastPrefixToken.endOffset() + suffixToken.startOffset());
157     suffixToken.setEndOffset(lastPrefixToken.endOffset() + suffixToken.endOffset());
158     return suffixToken;
159   }
160
161   @Override
162   public void end() throws IOException {
163     prefix.end();
164     suffix.end();
165   }
166
167   @Override
168   public void close() throws IOException {
169     prefix.close();
170     suffix.close();
171   }
172
173   @Override
174   public void reset() throws IOException {
175     super.reset();
176     if (prefix != null) {
177       prefixExhausted = false;
178       prefix.reset();
179     }
180     if (suffix != null) {
181       suffix.reset();
182     }
183
184
185   }
186
187   public TokenStream getPrefix() {
188     return prefix;
189   }
190
191   public void setPrefix(TokenStream prefix) {
192     this.prefix = prefix;
193   }
194
195   public TokenStream getSuffix() {
196     return suffix;
197   }
198
199   public void setSuffix(TokenStream suffix) {
200     this.suffix = suffix;
201   }
202 }