/* Copyright 2013 Fabian Steeg, hbz. Licensed under the Eclipse Public License 1.0 */
package models;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.elasticsearch.search.SearchHit;
import com.fasterxml.jackson.databind.JsonNode;
import play.Logger;
import play.libs.Json;
/**
* Process different kinds of result hits.
*
* @author Fabian Steeg (fsteeg)
*/
public enum Hit {
/***/
LIST(List.class) {
@Override
Document process(final String query, final Document document) {
final List<?> list = (List<?>) field;
if (list.get(0) instanceof String) {
STRING.process(query, document);
} else if (list.get(0) instanceof Map) {
@SuppressWarnings("unchecked")
final List<Map<String, Object>> maps =
(List<Map<String, Object>>) field;
processMaps(query, document, maps);
}
return document;
}
},
/***/
STRING(String.class) {
@Override
Document process(final String query, final Document document) {
if (fields.get(0).contains("preferredNameForThePerson")) {
final JsonNode json = Json.toJson(hit.getSource());
final JsonNode birth = findNestedValue(json, fields.get(1));
final JsonNode death = findNestedValue(json, fields.get(2));
if (birth == null)
document.matchedField = field.toString();
else {
final String format = String.format("%s (%s-%s)", field.toString(),
birth.asText(), death == null ? "" : death.asText());
document.matchedField = format;
}
} else {
try {
document.matchedField = field.toString();
} catch (NullPointerException npe) {
document.matchedField = "null";
Logger
.warn(npe.toString() + "\nsetting document.matchedField to null");
}
}
return document;
}
private JsonNode findNestedValue(final JsonNode json,
final String fieldName) {
final String stripped =
fieldName.replace(GRAPH_KEY + ".", "").replace("." + VALUE_KEY, "");
final JsonNode element = json.findValue(stripped);
return element == null ? null : element.findValue("@value");
}
},
/***/
MAP(Map.class) {
@Override
Document process(final String query, final Document document) {
@SuppressWarnings("unchecked")
final Map<String, Object> map = (Map<String, Object>) field;
processMaps(query, document, Arrays.asList(map));
return document;
}
};
private static Object field;
private static List<String> fields;
private static SearchHit hit;
private final Class<?> fieldType; // NOPMD
private static final String GRAPH_KEY = "@graph";
private static final String VALUE_KEY = "@value";
private static final String ID_KEY = "@id";
static Hit of(final SearchHit searchHit, final List<String> searchFields) { // NOPMD
hit = searchHit;
fields = searchFields;
field = firstExisting();
for (Hit hitElement : values()) {
if (hitElement.fieldType.isInstance(field)) {
return hitElement;
}
}
throw new IllegalArgumentException("No hit type for field: " + field);
}
private static String firstExisting() {
for (String currentField : fields) {
final String searchField = currentField /*@formatter:off*/
.replace(GRAPH_KEY + ".", "")
.replace("." + ID_KEY, "")
.replace("." + VALUE_KEY, ""); /*@formatter:on*/
final JsonNode value =
Json.toJson(hit.getSource()).findValue(searchField);
if (value != null) {
final JsonNode nestedId = value.findValue(ID_KEY);
if (nestedId != null)
return nestedId.asText();
final JsonNode nestedValue = value.findValue(VALUE_KEY);
if (nestedValue != null)
return nestedValue.asText();
if (!value.asText().trim().isEmpty())
return value.asText();
}
}
if (fields.contains("_all"))
return hit.getId();
Logger.warn(String.format("Hit '%s' contains none of the fields: '%s'",
hit.getSource(), fields));
return null;
}
private static void processMaps(final String query, final Document document,
final List<Map<String, Object>> maps) {
for (Map<String, Object> map : maps) {
if (map.get(ID_KEY).toString().contains(query)) {
document.matchedField = map.get(ID_KEY).toString();
break;
}
}
}
Hit(final Class<?> fieldType) {
this.fieldType = fieldType;
}
abstract Document process(String query, Document document);
}