blob: b1a9378710cf4bc5b2b4d79e390b09b8324fa7e9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.analysis;
import java.io.Reader;
/**
* An analyzer wrapper, that doesn't allow to wrap components or readers.
* By disallowing it, it means that the thread local resources can be delegated
* to the delegate analyzer, and not also be allocated on this analyzer.
* This wrapper class is the base class of all analyzers that just delegate to
* another analyzer, e.g. per field name.
*
* <p>This solves the problem of per field analyzer wrapper, where it also
* maintains a thread local per field token stream components, while it can
* safely delegate those and not also hold these data structures, which can
* become expensive memory wise.
*
* <p><b>Please note:</b> This analyzer uses a private {@link Analyzer.ReuseStrategy},
* which is returned by {@link #getReuseStrategy()}. This strategy is used when
* delegating. If you wrap this analyzer again and reuse this strategy, no
* delegation is done and the given fallback is used.
*
* @since 4.10.0
*/
public abstract class DelegatingAnalyzerWrapper extends AnalyzerWrapper {
/**
* Constructor.
* @param fallbackStrategy is the strategy to use if delegation is not possible
* This is to support the common pattern:
* {@code new OtherWrapper(thisWrapper.getReuseStrategy())}
*/
protected DelegatingAnalyzerWrapper(ReuseStrategy fallbackStrategy) {
super(new DelegatingReuseStrategy(fallbackStrategy));
// häckidy-hick-hack, because we cannot call super() with a reference to "this":
((DelegatingReuseStrategy) getReuseStrategy()).wrapper = this;
}
@Override
protected final TokenStreamComponents wrapComponents(String fieldName, TokenStreamComponents components) {
return super.wrapComponents(fieldName, components);
}
@Override
protected final TokenStream wrapTokenStreamForNormalization(String fieldName, TokenStream in) {
return super.wrapTokenStreamForNormalization(fieldName, in);
}
@Override
protected final Reader wrapReader(String fieldName, Reader reader) {
return super.wrapReader(fieldName, reader);
}
@Override
protected final Reader wrapReaderForNormalization(String fieldName, Reader reader) {
return super.wrapReaderForNormalization(fieldName, reader);
}
private static final class DelegatingReuseStrategy extends ReuseStrategy {
DelegatingAnalyzerWrapper wrapper;
private final ReuseStrategy fallbackStrategy;
DelegatingReuseStrategy(ReuseStrategy fallbackStrategy) {
this.fallbackStrategy = fallbackStrategy;
}
@Override
public TokenStreamComponents getReusableComponents(Analyzer analyzer, String fieldName) {
if (analyzer == wrapper) {
final Analyzer wrappedAnalyzer = wrapper.getWrappedAnalyzer(fieldName);
return wrappedAnalyzer.getReuseStrategy().getReusableComponents(wrappedAnalyzer, fieldName);
} else {
return fallbackStrategy.getReusableComponents(analyzer, fieldName);
}
}
@Override
public void setReusableComponents(Analyzer analyzer, String fieldName, TokenStreamComponents components) {
if (analyzer == wrapper) {
final Analyzer wrappedAnalyzer = wrapper.getWrappedAnalyzer(fieldName);
wrappedAnalyzer.getReuseStrategy().setReusableComponents(wrappedAnalyzer, fieldName, components);
} else {
fallbackStrategy.setReusableComponents(analyzer, fieldName, components);
}
}
};
}