blob: b9f58f0b070404c907b98d8b95bd1446775c7c46 [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.solr.handler.extraction;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.SafeXMLParsing;
import org.apache.tika.parser.ParseContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ParseContextConfig {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final Map<Class<?>, Object> entries = new HashMap<>();
/** Creates an empty Config without any settings (used as placeholder). */
public ParseContextConfig() {
}
/** Creates a {@code ParseContextConfig} from the given XML DOM element. */
public ParseContextConfig(SolrResourceLoader resourceLoader, Element element) throws Exception {
extract(element, resourceLoader);
}
/** Creates a {@code ParseContextConfig} from the given XML file, loaded from the given {@link SolrResourceLoader}. */
public ParseContextConfig(SolrResourceLoader resourceLoader, String parseContextConfigLoc) throws Exception {
this(resourceLoader, loadConfigFile(resourceLoader, parseContextConfigLoc).getDocumentElement());
}
private static Document loadConfigFile(SolrResourceLoader resourceLoader, String parseContextConfigLoc) throws Exception {
return SafeXMLParsing.parseConfigXML(log, resourceLoader, parseContextConfigLoc);
}
private void extract(Element element, SolrResourceLoader loader) throws Exception {
final NodeList xmlEntries = element.getElementsByTagName("entry");
for (int i = 0, c1 = xmlEntries.getLength(); i < c1; i++) {
final NamedNodeMap xmlEntryAttributes = xmlEntries.item(i).getAttributes();
final String className = xmlEntryAttributes.getNamedItem("class").getNodeValue();
final String implementationName = xmlEntryAttributes.getNamedItem("impl").getNodeValue();
final NodeList xmlProperties = ((Element)xmlEntries.item(i)).getElementsByTagName("property");
final Class<?> interfaceClass = loader.findClass(className, Object.class);
final BeanInfo beanInfo = Introspector.getBeanInfo(interfaceClass, Introspector.IGNORE_ALL_BEANINFO);
final HashMap<String, PropertyDescriptor> descriptorMap = new HashMap<>();
for (final PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
descriptorMap.put(pd.getName(), pd);
}
final Object instance = loader.newInstance(implementationName, Object.class);
if (!interfaceClass.isInstance(instance)) {
throw new IllegalArgumentException("Implementation class does not extend " + interfaceClass.getName());
}
for (int j = 0, c2 = xmlProperties.getLength(); j < c2; j++) {
final Node xmlProperty = xmlProperties.item(j);
final NamedNodeMap xmlPropertyAttributes = xmlProperty.getAttributes();
final String propertyName = xmlPropertyAttributes.getNamedItem("name").getNodeValue();
final String propertyValue = xmlPropertyAttributes.getNamedItem("value").getNodeValue();
final PropertyDescriptor propertyDescriptor = descriptorMap.get(propertyName);
if (propertyDescriptor == null) {
throw new IllegalArgumentException(String.format(Locale.ENGLISH, "Unknown bean property %s in class %s",
propertyName, interfaceClass.getName()));
}
final Method method = propertyDescriptor.getWriteMethod();
if (method == null) {
throw new IllegalArgumentException(String.format(Locale.ENGLISH, "Cannot set bean property %s in class %s (no write method available)",
propertyName, interfaceClass.getName()));
}
method.invoke(instance, getValueFromString(propertyDescriptor.getPropertyType(), propertyValue));
}
entries.put(interfaceClass, instance);
}
}
private Object getValueFromString(Class<?> targetType, String text) {
final PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
if (editor == null) {
throw new IllegalArgumentException("Cannot set properties of type " + targetType.getName());
}
editor.setAsText(text);
return editor.getValue();
}
@SuppressWarnings({"rawtypes", "unchecked"})
public ParseContext create() {
final ParseContext result = new ParseContext();
for (Map.Entry<Class<?>, Object> entry : entries.entrySet()){
result.set((Class) entry.getKey(), entry.getValue());
}
return result;
}
}