package com.constellio.data.dao.services.solr;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrInputDocument;
import com.constellio.data.utils.ImpossibleRuntimeException;
public class ConstellioSolrInputDocument extends SolrInputDocument {
@Override
public void setField(String name, Object value) {
value = convertEmptyToNull(value);
if (value == null) {
super.remove(name);
} else {
validate(name, value);
super.setField(name, value);
}
}
@Override
public void setField(String name, Object value, float boost) {
value = convertEmptyToNull(value);
if (value == null) {
super.remove(name);
} else {
validate(name, value);
super.setField(name, value, boost);
}
}
@Override
public void addField(String name, Object value, float boost) {
value = convertEmptyToNull(value);
if (value == null) {
super.remove(name);
} else {
validate(name, value);
super.addField(name, value, boost);
}
}
private Object convertEmptyToNull(Object value) {
if (value instanceof List) {
List newValue = new ArrayList((List) value);
Iterator valueIterator = newValue.iterator();
while (valueIterator.hasNext()) {
Object currentValue = valueIterator.next();
if (currentValue instanceof String && StringUtils.isEmpty(currentValue.toString())) {
valueIterator.remove();
}
}
return newValue;
} else if (value instanceof Map) {
Map newValueMap = new HashMap((Map) value);
Set<Entry> valueList = ((Map) value).entrySet();
Iterator<Map.Entry> valueIterator = valueList.iterator();
while (valueIterator.hasNext()) {
Map.Entry currentValue = valueIterator.next();
if (currentValue.getValue() instanceof String && StringUtils.isEmpty(currentValue.getValue().toString())) {
newValueMap.put(currentValue.getKey(), null);
}
}
return newValueMap;
} else if (value instanceof String && StringUtils.isEmpty(value.toString())) {
return null;
} else {
return value;
}
}
private void validate(String name, Object value) {
if (name == null) {
throw new ImpossibleRuntimeException("field name must not be null");
}
if (value == null) {
throw new ImpossibleRuntimeException("value of field '" + name + "' must not be null");
}
if (name.equals("id") && !(value instanceof String)) {
throw new ImpossibleRuntimeException("id field must be not null and a string");
}
if (value instanceof List) {
for (Object item : (List) value) {
if (item == null) {
throw new ImpossibleRuntimeException("value of field '" + name + "' must not contain null values");
}
}
}
if (value instanceof Map) {
for (Object item : ((Map) value).values()) {
// if (item == null) {
// throw new ImpossibleRuntimeException("value of field '" + name + "' must not contain null values");
// }
if (item instanceof List) {
for (Object mapValueItem : (List) item) {
if (mapValueItem == null) {
throw new ImpossibleRuntimeException("value of field '" + name + "' must not contain null values");
}
}
}
}
}
if (name.endsWith("_da") || name.endsWith("_dt")) {
ensureValueIsOfClass(name, value, String.class);
}
if (name.endsWith("_das") || name.endsWith("_dts")) {
ensureValueIsListOfClass(name, value, String.class);
}
}
private void ensureValueIsOfClass(String fieldName, Object value, Class<?> expectedValueClass) {
if (value instanceof Map) {
Map<Object, Object> map = (Map) value;
Object firstEntryValue = map.entrySet().iterator().next().getValue();
ensureValueIsOfClass(fieldName, firstEntryValue, expectedValueClass);
} else if (value != null && !expectedValueClass.isAssignableFrom(value.getClass())) {
throw new ImpossibleRuntimeException(
"value of field '" + fieldName + "' must be a " + expectedValueClass.getSimpleName() + " instead of a "
+ value.getClass().getSimpleName());
}
}
private void ensureValueIsListOfClass(String fieldName, Object value, Class<?> expectedValueClass) {
if (value instanceof Map) {
Map<Object, Object> map = (Map) value;
Object firstEntryValue = map.entrySet().iterator().next().getValue();
ensureValueIsListOfClass(fieldName, firstEntryValue, expectedValueClass);
} else if (value != null) {
if (!(value instanceof List)) {
throw new ImpossibleRuntimeException(
"value of field '" + fieldName + "' must be a List, but is of class " + value.getClass());
}
List<Object> list = (List) value;
for (Object item : list) {
ensureValueIsOfClass(fieldName, item, expectedValueClass);
}
}
}
}