~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to lucene/src/java/org/apache/lucene/analysis/Token.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.apache.lucene.analysis;
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.tokenattributes.TermAttributeImpl;
21
 
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
22
 
import org.apache.lucene.analysis.tokenattributes.FlagsAttribute;
23
 
import org.apache.lucene.analysis.tokenattributes.PayloadAttribute;
24
 
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
25
 
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
26
 
import org.apache.lucene.index.Payload;
27
 
import org.apache.lucene.index.TermPositions;     // for javadoc
28
 
import org.apache.lucene.util.Attribute;
29
 
import org.apache.lucene.util.AttributeSource;
30
 
import org.apache.lucene.util.AttributeImpl;
31
 
import org.apache.lucene.util.AttributeReflector;
32
 
 
33
 
/** 
34
 
  A Token is an occurrence of a term from the text of a field.  It consists of
35
 
  a term's text, the start and end offset of the term in the text of the field,
36
 
  and a type string.
37
 
  <p>
38
 
  The start and end offsets permit applications to re-associate a token with
39
 
  its source text, e.g., to display highlighted query terms in a document
40
 
  browser, or to show matching text fragments in a <abbr title="KeyWord In Context">KWIC</abbr>
41
 
  display, etc.
42
 
  <p>
43
 
  The type is a string, assigned by a lexical analyzer
44
 
  (a.k.a. tokenizer), naming the lexical or syntactic class that the token
45
 
  belongs to.  For example an end of sentence marker token might be implemented
46
 
  with type "eos".  The default token type is "word".  
47
 
  <p>
48
 
  A Token can optionally have metadata (a.k.a. Payload) in the form of a variable
49
 
  length byte array. Use {@link TermPositions#getPayloadLength()} and 
50
 
  {@link TermPositions#getPayload(byte[], int)} to retrieve the payloads from the index.
51
 
  
52
 
  <br><br>
53
 
  
54
 
  <p><b>NOTE:</b> As of 2.9, Token implements all {@link Attribute} interfaces
55
 
  that are part of core Lucene and can be found in the {@code tokenattributes} subpackage.
56
 
  Even though it is not necessary to use Token anymore, with the new TokenStream API it can
57
 
  be used as convenience class that implements all {@link Attribute}s, which is especially useful
58
 
  to easily switch from the old to the new TokenStream API.
59
 
  
60
 
  <br><br>
61
 
  
62
 
  <p>Tokenizers and TokenFilters should try to re-use a Token
63
 
  instance when possible for best performance, by
64
 
  implementing the {@link TokenStream#incrementToken()} API.
65
 
  Failing that, to create a new Token you should first use
66
 
  one of the constructors that starts with null text.  To load
67
 
  the token from a char[] use {@link #copyBuffer(char[], int, int)}.
68
 
  To load from a String use {@link #setEmpty} followed by {@link #append(CharSequence)} or {@link #append(CharSequence, int, int)}.
69
 
  Alternatively you can get the Token's termBuffer by calling either {@link #buffer()},
70
 
  if you know that your text is shorter than the capacity of the termBuffer
71
 
  or {@link #resizeBuffer(int)}, if there is any possibility
72
 
  that you may need to grow the buffer. Fill in the characters of your term into this
73
 
  buffer, with {@link String#getChars(int, int, char[], int)} if loading from a string,
74
 
  or with {@link System#arraycopy(Object, int, Object, int, int)}, and finally call {@link #setLength(int)} to
75
 
  set the length of the term text.  See <a target="_top"
76
 
  href="https://issues.apache.org/jira/browse/LUCENE-969">LUCENE-969</a>
77
 
  for details.</p>
78
 
  <p>Typical Token reuse patterns:
79
 
  <ul>
80
 
  <li> Copying text from a string (type is reset to {@link #DEFAULT_TYPE} if not specified):<br/>
81
 
  <pre>
82
 
    return reusableToken.reinit(string, startOffset, endOffset[, type]);
83
 
  </pre>
84
 
  </li>
85
 
  <li> Copying some text from a string (type is reset to {@link #DEFAULT_TYPE} if not specified):<br/>
86
 
  <pre>
87
 
    return reusableToken.reinit(string, 0, string.length(), startOffset, endOffset[, type]);
88
 
  </pre>
89
 
  </li>
90
 
  </li>
91
 
  <li> Copying text from char[] buffer (type is reset to {@link #DEFAULT_TYPE} if not specified):<br/>
92
 
  <pre>
93
 
    return reusableToken.reinit(buffer, 0, buffer.length, startOffset, endOffset[, type]);
94
 
  </pre>
95
 
  </li>
96
 
  <li> Copying some text from a char[] buffer (type is reset to {@link #DEFAULT_TYPE} if not specified):<br/>
97
 
  <pre>
98
 
    return reusableToken.reinit(buffer, start, end - start, startOffset, endOffset[, type]);
99
 
  </pre>
100
 
  </li>
101
 
  <li> Copying from one one Token to another (type is reset to {@link #DEFAULT_TYPE} if not specified):<br/>
102
 
  <pre>
103
 
    return reusableToken.reinit(source.buffer(), 0, source.length(), source.startOffset(), source.endOffset()[, source.type()]);
104
 
  </pre>
105
 
  </li>
106
 
  </ul>
107
 
  A few things to note:
108
 
  <ul>
109
 
  <li>clear() initializes all of the fields to default values. This was changed in contrast to Lucene 2.4, but should affect no one.</li>
110
 
  <li>Because <code>TokenStreams</code> can be chained, one cannot assume that the <code>Token's</code> current type is correct.</li>
111
 
  <li>The startOffset and endOffset represent the start and offset in the source text, so be careful in adjusting them.</li>
112
 
  <li>When caching a reusable token, clone it. When injecting a cached token into a stream that can be reset, clone it again.</li>
113
 
  </ul>
114
 
  </p>
115
 
  <p>
116
 
  <b>Please note:</b> With Lucene 3.1, the <code>{@linkplain #toString toString()}</code> method had to be changed to match the
117
 
  {@link CharSequence} interface introduced by the interface {@link org.apache.lucene.analysis.tokenattributes.CharTermAttribute}.
118
 
  This method now only prints the term text, no additional information anymore.
119
 
  </p>
120
 
  @see org.apache.lucene.index.Payload
121
 
*/
122
 
// TODO: change superclass to CharTermAttribute in 4.0! Maybe deprecate the whole class?
123
 
public class Token extends TermAttributeImpl 
124
 
                   implements TypeAttribute, PositionIncrementAttribute,
125
 
                              FlagsAttribute, OffsetAttribute, PayloadAttribute {
126
 
 
127
 
  private int startOffset,endOffset;
128
 
  private String type = DEFAULT_TYPE;
129
 
  private int flags;
130
 
  private Payload payload;
131
 
  private int positionIncrement = 1;
132
 
 
133
 
  /** Constructs a Token will null text. */
134
 
  public Token() {
135
 
  }
136
 
 
137
 
  /** Constructs a Token with null text and start & end
138
 
   *  offsets.
139
 
   *  @param start start offset in the source text
140
 
   *  @param end end offset in the source text */
141
 
  public Token(int start, int end) {
142
 
    startOffset = start;
143
 
    endOffset = end;
144
 
  }
145
 
 
146
 
  /** Constructs a Token with null text and start & end
147
 
   *  offsets plus the Token type.
148
 
   *  @param start start offset in the source text
149
 
   *  @param end end offset in the source text
150
 
   *  @param typ the lexical type of this Token */
151
 
  public Token(int start, int end, String typ) {
152
 
    startOffset = start;
153
 
    endOffset = end;
154
 
    type = typ;
155
 
  }
156
 
 
157
 
  /**
158
 
   * Constructs a Token with null text and start & end
159
 
   *  offsets plus flags. NOTE: flags is EXPERIMENTAL.
160
 
   *  @param start start offset in the source text
161
 
   *  @param end end offset in the source text
162
 
   *  @param flags The bits to set for this token
163
 
   */
164
 
  public Token(int start, int end, int flags) {
165
 
    startOffset = start;
166
 
    endOffset = end;
167
 
    this.flags = flags;
168
 
  }
169
 
 
170
 
  /** Constructs a Token with the given term text, and start
171
 
   *  & end offsets.  The type defaults to "word."
172
 
   *  <b>NOTE:</b> for better indexing speed you should
173
 
   *  instead use the char[] termBuffer methods to set the
174
 
   *  term text.
175
 
   *  @param text term text
176
 
   *  @param start start offset
177
 
   *  @param end end offset
178
 
   */
179
 
  public Token(String text, int start, int end) {
180
 
    append(text);
181
 
    startOffset = start;
182
 
    endOffset = end;
183
 
  }
184
 
 
185
 
  /** Constructs a Token with the given text, start and end
186
 
   *  offsets, & type.  <b>NOTE:</b> for better indexing
187
 
   *  speed you should instead use the char[] termBuffer
188
 
   *  methods to set the term text.
189
 
   *  @param text term text
190
 
   *  @param start start offset
191
 
   *  @param end end offset
192
 
   *  @param typ token type
193
 
   */
194
 
  public Token(String text, int start, int end, String typ) {
195
 
    append(text);
196
 
    startOffset = start;
197
 
    endOffset = end;
198
 
    type = typ;
199
 
  }
200
 
 
201
 
  /**
202
 
   *  Constructs a Token with the given text, start and end
203
 
   *  offsets, & type.  <b>NOTE:</b> for better indexing
204
 
   *  speed you should instead use the char[] termBuffer
205
 
   *  methods to set the term text.
206
 
   * @param text
207
 
   * @param start
208
 
   * @param end
209
 
   * @param flags token type bits
210
 
   */
211
 
  public Token(String text, int start, int end, int flags) {
212
 
    append(text);
213
 
    startOffset = start;
214
 
    endOffset = end;
215
 
    this.flags = flags;
216
 
  }
217
 
 
218
 
  /**
219
 
   *  Constructs a Token with the given term buffer (offset
220
 
   *  & length), start and end
221
 
   *  offsets
222
 
   * @param startTermBuffer
223
 
   * @param termBufferOffset
224
 
   * @param termBufferLength
225
 
   * @param start
226
 
   * @param end
227
 
   */
228
 
  public Token(char[] startTermBuffer, int termBufferOffset, int termBufferLength, int start, int end) {
229
 
    copyBuffer(startTermBuffer, termBufferOffset, termBufferLength);
230
 
    startOffset = start;
231
 
    endOffset = end;
232
 
  }
233
 
 
234
 
  /** Set the position increment.  This determines the position of this token
235
 
   * relative to the previous Token in a {@link TokenStream}, used in phrase
236
 
   * searching.
237
 
   *
238
 
   * <p>The default value is one.
239
 
   *
240
 
   * <p>Some common uses for this are:<ul>
241
 
   *
242
 
   * <li>Set it to zero to put multiple terms in the same position.  This is
243
 
   * useful if, e.g., a word has multiple stems.  Searches for phrases
244
 
   * including either stem will match.  In this case, all but the first stem's
245
 
   * increment should be set to zero: the increment of the first instance
246
 
   * should be one.  Repeating a token with an increment of zero can also be
247
 
   * used to boost the scores of matches on that token.
248
 
   *
249
 
   * <li>Set it to values greater than one to inhibit exact phrase matches.
250
 
   * If, for example, one does not want phrases to match across removed stop
251
 
   * words, then one could build a stop word filter that removes stop words and
252
 
   * also sets the increment to the number of stop words removed before each
253
 
   * non-stop word.  Then exact phrase queries will only match when the terms
254
 
   * occur with no intervening stop words.
255
 
   *
256
 
   * </ul>
257
 
   * @param positionIncrement the distance from the prior term
258
 
   * @see org.apache.lucene.index.TermPositions
259
 
   */
260
 
  public void setPositionIncrement(int positionIncrement) {
261
 
    if (positionIncrement < 0)
262
 
      throw new IllegalArgumentException
263
 
        ("Increment must be zero or greater: " + positionIncrement);
264
 
    this.positionIncrement = positionIncrement;
265
 
  }
266
 
 
267
 
  /** Returns the position increment of this Token.
268
 
   * @see #setPositionIncrement
269
 
   */
270
 
  public int getPositionIncrement() {
271
 
    return positionIncrement;
272
 
  }
273
 
 
274
 
  /** Returns this Token's starting offset, the position of the first character
275
 
    corresponding to this token in the source text.
276
 
 
277
 
    Note that the difference between endOffset() and startOffset() may not be
278
 
    equal to {@link #length}, as the term text may have been altered by a
279
 
    stemmer or some other filter. */
280
 
  public final int startOffset() {
281
 
    return startOffset;
282
 
  }
283
 
 
284
 
  /** Set the starting offset.
285
 
      @see #startOffset() */
286
 
  public void setStartOffset(int offset) {
287
 
    this.startOffset = offset;
288
 
  }
289
 
 
290
 
  /** Returns this Token's ending offset, one greater than the position of the
291
 
    last character corresponding to this token in the source text. The length
292
 
    of the token in the source text is (endOffset - startOffset). */
293
 
  public final int endOffset() {
294
 
    return endOffset;
295
 
  }
296
 
 
297
 
  /** Set the ending offset.
298
 
      @see #endOffset() */
299
 
  public void setEndOffset(int offset) {
300
 
    this.endOffset = offset;
301
 
  }
302
 
  
303
 
  /** Set the starting and ending offset.
304
 
  @see #startOffset() and #endOffset()*/
305
 
  public void setOffset(int startOffset, int endOffset) {
306
 
    this.startOffset = startOffset;
307
 
    this.endOffset = endOffset;
308
 
  }
309
 
 
310
 
  /** Returns this Token's lexical type.  Defaults to "word". */
311
 
  public final String type() {
312
 
    return type;
313
 
  }
314
 
 
315
 
  /** Set the lexical type.
316
 
      @see #type() */
317
 
  public final void setType(String type) {
318
 
    this.type = type;
319
 
  }
320
 
 
321
 
  /**
322
 
   * <p/>
323
 
   *
324
 
   * Get the bitset for any bits that have been set.  This is completely distinct from {@link #type()}, although they do share similar purposes.
325
 
   * The flags can be used to encode information about the token for use by other {@link org.apache.lucene.analysis.TokenFilter}s.
326
 
   *
327
 
   * 
328
 
   * @return The bits
329
 
   * @lucene.experimental While we think this is here to stay, we may want to change it to be a long.
330
 
   */
331
 
  public int getFlags() {
332
 
    return flags;
333
 
  }
334
 
 
335
 
  /**
336
 
   * @see #getFlags()
337
 
   */
338
 
  public void setFlags(int flags) {
339
 
    this.flags = flags;
340
 
  }
341
 
 
342
 
  /**
343
 
   * Returns this Token's payload.
344
 
   */ 
345
 
  public Payload getPayload() {
346
 
    return this.payload;
347
 
  }
348
 
 
349
 
  /** 
350
 
   * Sets this Token's payload.
351
 
   */
352
 
  public void setPayload(Payload payload) {
353
 
    this.payload = payload;
354
 
  }
355
 
  
356
 
  /** Resets the term text, payload, flags, and positionIncrement,
357
 
   * startOffset, endOffset and token type to default.
358
 
   */
359
 
  @Override
360
 
  public void clear() {
361
 
    super.clear();
362
 
    payload = null;
363
 
    positionIncrement = 1;
364
 
    flags = 0;
365
 
    startOffset = endOffset = 0;
366
 
    type = DEFAULT_TYPE;
367
 
  }
368
 
 
369
 
  @Override
370
 
  public Object clone() {
371
 
    Token t = (Token)super.clone();
372
 
    // Do a deep clone
373
 
    if (payload != null) {
374
 
      t.payload = (Payload) payload.clone();
375
 
    }
376
 
    return t;
377
 
  }
378
 
 
379
 
  /** Makes a clone, but replaces the term buffer &
380
 
   * start/end offset in the process.  This is more
381
 
   * efficient than doing a full clone (and then calling
382
 
   * {@link #copyBuffer}) because it saves a wasted copy of the old
383
 
   * termBuffer. */
384
 
  public Token clone(char[] newTermBuffer, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset) {
385
 
    final Token t = new Token(newTermBuffer, newTermOffset, newTermLength, newStartOffset, newEndOffset);
386
 
    t.positionIncrement = positionIncrement;
387
 
    t.flags = flags;
388
 
    t.type = type;
389
 
    if (payload != null)
390
 
      t.payload = (Payload) payload.clone();
391
 
    return t;
392
 
  }
393
 
 
394
 
  @Override
395
 
  public boolean equals(Object obj) {
396
 
    if (obj == this)
397
 
      return true;
398
 
 
399
 
    if (obj instanceof Token) {
400
 
      final Token other = (Token) obj;
401
 
      return (startOffset == other.startOffset &&
402
 
          endOffset == other.endOffset && 
403
 
          flags == other.flags &&
404
 
          positionIncrement == other.positionIncrement &&
405
 
          (type == null ? other.type == null : type.equals(other.type)) &&
406
 
          (payload == null ? other.payload == null : payload.equals(other.payload)) &&
407
 
          super.equals(obj)
408
 
      );
409
 
    } else
410
 
      return false;
411
 
  }
412
 
 
413
 
  @Override
414
 
  public int hashCode() {
415
 
    int code = super.hashCode();
416
 
    code = code * 31 + startOffset;
417
 
    code = code * 31 + endOffset;
418
 
    code = code * 31 + flags;
419
 
    code = code * 31 + positionIncrement;
420
 
    if (type != null)
421
 
      code = code * 31 + type.hashCode();
422
 
    if (payload != null)
423
 
      code = code * 31 + payload.hashCode();
424
 
    return code;
425
 
  }
426
 
      
427
 
  // like clear() but doesn't clear termBuffer/text
428
 
  private void clearNoTermBuffer() {
429
 
    payload = null;
430
 
    positionIncrement = 1;
431
 
    flags = 0;
432
 
    startOffset = endOffset = 0;
433
 
    type = DEFAULT_TYPE;
434
 
  }
435
 
 
436
 
  /** Shorthand for calling {@link #clear},
437
 
   *  {@link #copyBuffer(char[], int, int)},
438
 
   *  {@link #setStartOffset},
439
 
   *  {@link #setEndOffset},
440
 
   *  {@link #setType}
441
 
   *  @return this Token instance */
442
 
  public Token reinit(char[] newTermBuffer, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset, String newType) {
443
 
    clearNoTermBuffer();
444
 
    copyBuffer(newTermBuffer, newTermOffset, newTermLength);
445
 
    payload = null;
446
 
    positionIncrement = 1;
447
 
    startOffset = newStartOffset;
448
 
    endOffset = newEndOffset;
449
 
    type = newType;
450
 
    return this;
451
 
  }
452
 
 
453
 
  /** Shorthand for calling {@link #clear},
454
 
   *  {@link #copyBuffer(char[], int, int)},
455
 
   *  {@link #setStartOffset},
456
 
   *  {@link #setEndOffset}
457
 
   *  {@link #setType} on Token.DEFAULT_TYPE
458
 
   *  @return this Token instance */
459
 
  public Token reinit(char[] newTermBuffer, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset) {
460
 
    clearNoTermBuffer();
461
 
    copyBuffer(newTermBuffer, newTermOffset, newTermLength);
462
 
    startOffset = newStartOffset;
463
 
    endOffset = newEndOffset;
464
 
    type = DEFAULT_TYPE;
465
 
    return this;
466
 
  }
467
 
 
468
 
  /** Shorthand for calling {@link #clear},
469
 
   *  {@link #append(CharSequence)},
470
 
   *  {@link #setStartOffset},
471
 
   *  {@link #setEndOffset}
472
 
   *  {@link #setType}
473
 
   *  @return this Token instance */
474
 
  public Token reinit(String newTerm, int newStartOffset, int newEndOffset, String newType) {
475
 
    clear();
476
 
    append(newTerm);
477
 
    startOffset = newStartOffset;
478
 
    endOffset = newEndOffset;
479
 
    type = newType;
480
 
    return this;
481
 
  }
482
 
 
483
 
  /** Shorthand for calling {@link #clear},
484
 
   *  {@link #append(CharSequence, int, int)},
485
 
   *  {@link #setStartOffset},
486
 
   *  {@link #setEndOffset}
487
 
   *  {@link #setType}
488
 
   *  @return this Token instance */
489
 
  public Token reinit(String newTerm, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset, String newType) {
490
 
    clear();
491
 
    append(newTerm, newTermOffset, newTermOffset + newTermLength);
492
 
    startOffset = newStartOffset;
493
 
    endOffset = newEndOffset;
494
 
    type = newType;
495
 
    return this;
496
 
  }
497
 
 
498
 
  /** Shorthand for calling {@link #clear},
499
 
   *  {@link #append(CharSequence)},
500
 
   *  {@link #setStartOffset},
501
 
   *  {@link #setEndOffset}
502
 
   *  {@link #setType} on Token.DEFAULT_TYPE
503
 
   *  @return this Token instance */
504
 
  public Token reinit(String newTerm, int newStartOffset, int newEndOffset) {
505
 
    clear();
506
 
    append(newTerm);
507
 
    startOffset = newStartOffset;
508
 
    endOffset = newEndOffset;
509
 
    type = DEFAULT_TYPE;
510
 
    return this;
511
 
  }
512
 
 
513
 
  /** Shorthand for calling {@link #clear},
514
 
   *  {@link #append(CharSequence, int, int)},
515
 
   *  {@link #setStartOffset},
516
 
   *  {@link #setEndOffset}
517
 
   *  {@link #setType} on Token.DEFAULT_TYPE
518
 
   *  @return this Token instance */
519
 
  public Token reinit(String newTerm, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset) {
520
 
    clear();
521
 
    append(newTerm, newTermOffset, newTermOffset + newTermLength);
522
 
    startOffset = newStartOffset;
523
 
    endOffset = newEndOffset;
524
 
    type = DEFAULT_TYPE;
525
 
    return this;
526
 
  }
527
 
 
528
 
  /**
529
 
   * Copy the prototype token's fields into this one. Note: Payloads are shared.
530
 
   * @param prototype
531
 
   */
532
 
  public void reinit(Token prototype) {
533
 
    copyBuffer(prototype.buffer(), 0, prototype.length());
534
 
    positionIncrement = prototype.positionIncrement;
535
 
    flags = prototype.flags;
536
 
    startOffset = prototype.startOffset;
537
 
    endOffset = prototype.endOffset;
538
 
    type = prototype.type;
539
 
    payload =  prototype.payload;
540
 
  }
541
 
 
542
 
  /**
543
 
   * Copy the prototype token's fields into this one, with a different term. Note: Payloads are shared.
544
 
   * @param prototype
545
 
   * @param newTerm
546
 
   */
547
 
  public void reinit(Token prototype, String newTerm) {
548
 
    setEmpty().append(newTerm);
549
 
    positionIncrement = prototype.positionIncrement;
550
 
    flags = prototype.flags;
551
 
    startOffset = prototype.startOffset;
552
 
    endOffset = prototype.endOffset;
553
 
    type = prototype.type;
554
 
    payload =  prototype.payload;
555
 
  }
556
 
 
557
 
  /**
558
 
   * Copy the prototype token's fields into this one, with a different term. Note: Payloads are shared.
559
 
   * @param prototype
560
 
   * @param newTermBuffer
561
 
   * @param offset
562
 
   * @param length
563
 
   */
564
 
  public void reinit(Token prototype, char[] newTermBuffer, int offset, int length) {
565
 
    copyBuffer(newTermBuffer, offset, length);
566
 
    positionIncrement = prototype.positionIncrement;
567
 
    flags = prototype.flags;
568
 
    startOffset = prototype.startOffset;
569
 
    endOffset = prototype.endOffset;
570
 
    type = prototype.type;
571
 
    payload =  prototype.payload;
572
 
  }
573
 
 
574
 
  @Override
575
 
  public void copyTo(AttributeImpl target) {
576
 
    if (target instanceof Token) {
577
 
      final Token to = (Token) target;
578
 
      to.reinit(this);
579
 
      // reinit shares the payload, so clone it:
580
 
      if (payload !=null) {
581
 
        to.payload = (Payload) payload.clone();
582
 
      }
583
 
    } else {
584
 
      super.copyTo(target);
585
 
      ((OffsetAttribute) target).setOffset(startOffset, endOffset);
586
 
      ((PositionIncrementAttribute) target).setPositionIncrement(positionIncrement);
587
 
      ((PayloadAttribute) target).setPayload((payload == null) ? null : (Payload) payload.clone());
588
 
      ((FlagsAttribute) target).setFlags(flags);
589
 
      ((TypeAttribute) target).setType(type);
590
 
    }
591
 
  }
592
 
 
593
 
  @Override
594
 
  public void reflectWith(AttributeReflector reflector) {
595
 
    super.reflectWith(reflector);
596
 
    reflector.reflect(OffsetAttribute.class, "startOffset", startOffset);
597
 
    reflector.reflect(OffsetAttribute.class, "endOffset", endOffset);
598
 
    reflector.reflect(PositionIncrementAttribute.class, "positionIncrement", positionIncrement);
599
 
    reflector.reflect(PayloadAttribute.class, "payload", payload);
600
 
    reflector.reflect(FlagsAttribute.class, "flags", flags);
601
 
    reflector.reflect(TypeAttribute.class, "type", type);
602
 
  }
603
 
 
604
 
  /** Convenience factory that returns <code>Token</code> as implementation for the basic
605
 
   * attributes and return the default impl (with &quot;Impl&quot; appended) for all other
606
 
   * attributes.
607
 
   * @since 3.0
608
 
   */
609
 
  public static final AttributeSource.AttributeFactory TOKEN_ATTRIBUTE_FACTORY =
610
 
    new TokenAttributeFactory(AttributeSource.AttributeFactory.DEFAULT_ATTRIBUTE_FACTORY);
611
 
  
612
 
  /** <b>Expert:</b> Creates a TokenAttributeFactory returning {@link Token} as instance for the basic attributes
613
 
   * and for all other attributes calls the given delegate factory.
614
 
   * @since 3.0
615
 
   */
616
 
  public static final class TokenAttributeFactory extends AttributeSource.AttributeFactory {
617
 
    
618
 
    private final AttributeSource.AttributeFactory delegate;
619
 
    
620
 
    /** <b>Expert</b>: Creates an AttributeFactory returning {@link Token} as instance for the basic attributes
621
 
     * and for all other attributes calls the given delegate factory. */
622
 
    public TokenAttributeFactory(AttributeSource.AttributeFactory delegate) {
623
 
      this.delegate = delegate;
624
 
    }
625
 
  
626
 
    @Override
627
 
    public AttributeImpl createAttributeInstance(Class<? extends Attribute> attClass) {
628
 
      return attClass.isAssignableFrom(Token.class)
629
 
        ? new Token() : delegate.createAttributeInstance(attClass);
630
 
    }
631
 
    
632
 
    @Override
633
 
    public boolean equals(Object other) {
634
 
      if (this == other) return true;
635
 
      if (other instanceof TokenAttributeFactory) {
636
 
        final TokenAttributeFactory af = (TokenAttributeFactory) other;
637
 
        return this.delegate.equals(af.delegate);
638
 
      }
639
 
      return false;
640
 
    }
641
 
    
642
 
    @Override
643
 
    public int hashCode() {
644
 
      return delegate.hashCode() ^ 0x0a45aa31;
645
 
    }
646
 
  }
647
 
 
648
 
}