/*
* Copyright (c) 2011 LinkedIn, Inc
*
* Licensed 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 com.flaptor.indextank.query.analyzers;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import com.google.common.collect.Lists;
public class FilteringAnalyzer extends Analyzer {
private List<AnalyzerFilter> filters = Lists.newArrayList();
private final Analyzer original;
/**
* Constructs the Analyzer's filter given its configuration. Will only consider a
* "filters" key in the root object. The value for this key has to be a list
* of maps each one with the keys "factory" (string) and "configuration" (map).
* Factory needs to be a class name for a class with a static method:
* AnalyzerFilter buildFilter(Map)
*
* @param filtersConfiguration
*/
public FilteringAnalyzer(Analyzer original, Map<Object, Object> analyzerConfiguration) {
this.original = original;
String key = "filters";
if (analyzerConfiguration.containsKey(key)) {
List<Map<Object, Object>> filtersConfigurations;
try {
filtersConfigurations = (List<Map<Object, Object>>) analyzerConfiguration.get(key);
} catch (ClassCastException e) {
throw new IllegalArgumentException("Value for 'filters' key should be a List<Map>", e);
}
for (Map<Object, Object> filter : filtersConfigurations) {
String factoryClassString;
Map<Object, Object> factoryConfiguration;
try {
factoryClassString = (String) filter.get("factory");
factoryConfiguration = (Map<Object, Object>) filter.get("configuration");
} catch (ClassCastException e) {
throw new IllegalArgumentException("Value for 'factory' should be a String with the factory class name, 'configuration' should be a map.", e);
}
try {
Class<?> factoryClass = Class.forName(factoryClassString);
Method method = factoryClass.getMethod("buildFilter", new Class[] {Map.class});
AnalyzerFilter tokenFilter = (AnalyzerFilter) method.invoke(null, factoryConfiguration);
filters.add(tokenFilter);
} catch (ClassCastException e) {
throw new RuntimeException("Filter factory method does not return an AnalyzerFilter", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Filter factory class not found", e);
} catch (SecurityException e) {
throw new RuntimeException("Filter factory class not instantiable", e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Filter factory class does not have the required static method buildFilter", e);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Filter factory class does not have the required static method buildFilter", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Filter factory class does not have the required static method buildFilter or it is not accessible", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Filter factory class threw an exception for the give configuration", e);
}
}
}
}
@Override
public final TokenStream tokenStream(String fieldName, Reader reader) {
TokenStream result = analyzePreFilters(fieldName, reader);
for (AnalyzerFilter filter : filters) {
result = filter.filter(result);
}
return result;
}
private TokenStream analyzePreFilters(String fieldName, Reader reader) {
return original.tokenStream(fieldName, reader);
}
}