Impl
to it.
+ */
+ public static final AttributeFactory DEFAULT_ATTRIBUTE_FACTORY = new DefaultAttributeFactory();
+
+ private static final class DefaultAttributeFactory extends AttributeFactory {
+ private static final WeakHashMapPlease note: It is not guaranteed, that att
is added to
+ * the AttributeSource
, because the provided attributes may already exist.
+ * You should always retrieve the wanted attributes using {@link #getAttribute} after adding
+ * with this method and cast to your class.
+ * The recommended way to use custom implementations is using an {@link AttributeFactory}.
+ *
+ * Note that this method does not affect attributes of the targetStream + * that are not contained in this state. In other words, if for example + * the targetStream contains an OffsetAttribute, but this state doesn't, then + * the value of the OffsetAttribute remains unchanged. It might be desirable to + * reset its value to the default, in which case the caller should first + * call {@link TokenStream#clearAttributes()} on the targetStream. + */ + public void restoreState(State state) { + if (state == null) return; + + do { + AttributeImpl targetImpl = attributeImpls.get(state.attribute.getClass()); + if (targetImpl == null) { + throw new IllegalArgumentException("State contains AttributeImpl of type " + + state.attribute.getClass().getName() + " that is not in in this AttributeSource"); + } + state.attribute.copyTo(targetImpl); + state = state.next; + } while (state != null); + } + + @Override + public int hashCode() { + int code = 0; + for (State state = getCurrentState(); state != null; state = state.next) { + code = code * 31 + state.attribute.hashCode(); + } + return code; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj instanceof AttributeSource) { + AttributeSource other = (AttributeSource) obj; + + if (hasAttributes()) { + if (!other.hasAttributes()) { + return false; + } + + if (this.attributeImpls.size() != other.attributeImpls.size()) { + return false; + } + + // it is only equal if all attribute impls are the same in the same order + State thisState = this.getCurrentState(); + State otherState = other.getCurrentState(); + while (thisState != null && otherState != null) { + if (otherState.attribute.getClass() != thisState.attribute.getClass() || !otherState.attribute.equals(thisState.attribute)) { + return false; + } + thisState = thisState.next; + otherState = otherState.next; + } + return true; + } else { + return !other.hasAttributes(); + } + } else + return false; + } + + /** + * Returns a string representation of the object. In general, the {@code toString} method + * returns a string that "textually represents" this object. + * + *
WARNING: For backwards compatibility this method is implemented as + * in Lucene 2.9/3.0. In Lucene 4.0 this default implementation + * will be removed. + * + *
It is recommeneded to use {@link #reflectAsString} or {@link #reflectWith} + * to get a well-defined output of AttributeSource's internals. + */ + // TODO: @deprecated remove this method in 4.0 + @Override + public String toString() { + final StringBuilder sb = new StringBuilder().append('('); + if (hasAttributes()) { + for (State state = getCurrentState(); state != null; state = state.next) { + if (sb.length() > 1) sb.append(','); + sb.append(state.attribute.toString()); + } + } + return sb.append(')').toString(); + } + + /** + * This method returns the current attribute values as a string in the following format + * by calling the {@link #reflectWith(AttributeReflector)} method: + * + *
This method iterates over all Attribute implementations and calls the + * corresponding {@link AttributeImpl#reflectWith} method.
+ * + * @see AttributeImpl#reflectWith + */ + public final void reflectWith(AttributeReflector reflector) { + for (State state = getCurrentState(); state != null; state = state.next) { + state.attribute.reflectWith(reflector); + } + } + + /** + * Performs a clone of all {@link AttributeImpl} instances returned in a new + * {@code AttributeSource} instance. This method can be used to e.g. create another TokenStream + * with exactly the same attributes (using {@link #AttributeSource(AttributeSource)}). + * You can also use it as a (non-performant) replacement for {@link #captureState}, if you need to look + * into / modify the captured state. + */ + public AttributeSource cloneAttributes() { + final AttributeSource clone = new AttributeSource(this.factory); + + if (hasAttributes()) { + // first clone the impls + for (State state = getCurrentState(); state != null; state = state.next) { + clone.attributeImpls.put(state.attribute.getClass(), (AttributeImpl) state.attribute.clone()); + } + + // now the interfaces + for (Entry