/*
* JBoss, Home of Professional Open Source
* Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
*/
package org.jboss.elasticsearch.tools.content;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
/**
* Abstract base class for preprocessors supporting concept of "source_bases". Do not forgot to call parent
* {@link #init(Map)} from your subclass init method if you override it!
*
* @author Vlastimil Elias (velias at redhat dot com)
*/
public abstract class StructuredContentPreprocessorWithSourceBasesBase<T> extends StructuredContentPreprocessorBase {
protected static final String CFG_source_bases = "source_bases";
protected List<String> sourceBases;
@SuppressWarnings("unchecked")
@Override
public void init(Map<String, Object> settings) throws SettingsException {
if (settings == null) {
throw new SettingsException("'settings' section is not defined for preprocessor " + name);
}
sourceBases = (List<String>) settings.get(CFG_source_bases);
}
@SuppressWarnings("unchecked")
@Override
public Map<String, Object> preprocessData(Map<String, Object> data, PreprocessChainContext chainContext) {
if (data == null)
return null;
if (sourceBases == null) {
processOneSourceValue(data, null, null, chainContext);
} else {
T context = createContext(data);
for (String base : sourceBases) {
Object obj = XContentMapValues.extractValue(base, data);
if (obj != null) {
if (obj instanceof Map) {
processOneSourceValue((Map<String, Object>) obj, context, base, chainContext);
} else if (obj instanceof Collection) {
for (Object o : (Collection<Object>) obj) {
if (o instanceof Map) {
processOneSourceValue((Map<String, Object>) o, context, base, chainContext);
} else {
String msg = "Collection in field '" + base
+ "' contains value which is not Map, which can't be processed as source_base, so is skipped";
addDataWarning(chainContext, msg);
logger.debug(msg);
}
}
} else {
String msg = "Field '" + base
+ "' contains invalid value which can't be processed as source_base, so is skipped";
addDataWarning(chainContext, msg);
logger.debug(msg);
}
}
}
}
return data;
}
/**
* Do preprocessing of data. If "source_bases" concept is used then called multiple times for each base,
* <code>data<code> are relative for this base now.
*
* @param data to run preprocessing on.
* @param context from {@link #createContext()}
* @param base processing is called for. Can be null if not called for base. It is just for use in warning messages
* etc (for example {@link #getFullFieldName(String, String)}).
* @param chainContext preprocessor chain context
*/
protected abstract void processOneSourceValue(Map<String, Object> data, T context, String base,
PreprocessChainContext chainContext);
/**
* Create shared context object passed to each call of {@link #preprocessData(Map)} if "source_bases" concept is used.
* Not called when "source_bases" concept is not used.
*
* @param data complete data we run preprocessig for
* @return context object or null
*/
protected abstract T createContext(Map<String, Object> data);
/**
* Get full name of field in respect to base with dot notation.
*
* @param base field is for, can be null
* @param field we want full name for
* @return full name for field
*/
protected static String getFullFieldName(String base, String field) {
if (base != null) {
return base + "." + field;
} else {
return field;
}
}
/**
* Get configured source bases
*
* @return source bases or null if not configured
*/
public List<String> getSourceBases() {
return sourceBases;
}
}