/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.search.elasticsearch.internal.document;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.DocumentImpl;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.geolocation.GeoLocationPoint;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.search.elasticsearch.document.ElasticsearchDocumentFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.lang.time.FastDateFormat;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.osgi.service.component.annotations.Component;
/**
* @author Michael C. Han
* @author Milen Dyankov
*/
@Component(immediate = true, service = ElasticsearchDocumentFactory.class)
public class DefaultElasticsearchDocumentFactory
implements ElasticsearchDocumentFactory {
public static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance(
"yyyyMMddHHmmss");
public static final String DATE_MAX_VALUE = "99950812133000";
@Override
public String getElasticsearchDocument(Document document)
throws IOException {
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
xContentBuilder.startObject();
Map<String, Field> fields = document.getFields();
addFields(fields.values(), xContentBuilder);
xContentBuilder.endObject();
return xContentBuilder.string();
}
protected void addDates(XContentBuilder xContentBuilder, Field field)
throws IOException {
for (Date date : field.getDates()) {
String value;
if (date.getTime() == Long.MAX_VALUE) {
value = DATE_MAX_VALUE;
}
else {
value = DATE_FORMAT.format(date);
}
xContentBuilder.value(value);
}
}
protected void addField(XContentBuilder xContentBuilder, Field field)
throws IOException {
String name = field.getName();
if (!field.isLocalized()) {
String[] values = field.getValues();
if (ArrayUtil.isEmpty(values)) {
return;
}
List<String> valuesList = new ArrayList<>(values.length);
for (String value : values) {
if (value == null) {
continue;
}
valuesList.add(value.trim());
}
if (valuesList.isEmpty()) {
return;
}
values = valuesList.toArray(new String[valuesList.size()]);
addField(xContentBuilder, field, name, values);
if (field.isSortable()) {
String sortFieldName = DocumentImpl.getSortableFieldName(name);
addField(xContentBuilder, field, sortFieldName, values);
}
}
else {
Map<Locale, String> localizedValues = field.getLocalizedValues();
for (Map.Entry<Locale, String> entry : localizedValues.entrySet()) {
String value = entry.getValue();
if (Validator.isNull(value)) {
continue;
}
Locale locale = entry.getKey();
String languageId = LocaleUtil.toLanguageId(locale);
String defaultLanguageId = LocaleUtil.toLanguageId(
LocaleUtil.getDefault());
value = value.trim();
if (languageId.equals(defaultLanguageId)) {
addField(xContentBuilder, field, name, value);
}
String localizedName = DocumentImpl.getLocalizedName(
languageId, name);
addField(xContentBuilder, field, localizedName, value);
if (field.isSortable()) {
String sortableFieldName =
DocumentImpl.getSortableFieldName(localizedName);
addField(xContentBuilder, field, sortableFieldName, value);
}
}
}
}
protected void addField(
XContentBuilder xContentBuilder, Field field, String fieldName,
String... values)
throws IOException {
xContentBuilder.field(fieldName);
if (field.isArray() || (values.length > 1)) {
xContentBuilder.startArray();
}
GeoLocationPoint geoLocationPoint = field.getGeoLocationPoint();
if (geoLocationPoint != null) {
GeoPoint geoPoint = new GeoPoint(
geoLocationPoint.getLatitude(),
geoLocationPoint.getLongitude());
xContentBuilder.value(geoPoint);
}
else if (field.isDate()) {
addDates(xContentBuilder, field);
}
else {
for (String value : values) {
xContentBuilder.value(translateValue(field, value));
}
}
if (field.isArray() || (values.length > 1)) {
xContentBuilder.endArray();
}
}
protected void addFields(
Collection<Field> fields, XContentBuilder xContentBuilder)
throws IOException {
for (Field field : fields) {
if (!field.hasChildren()) {
addField(xContentBuilder, field);
}
else {
addNestedField(xContentBuilder, field);
}
}
}
protected void addNestedField(XContentBuilder xContentBuilder, Field field)
throws IOException {
if (field.isArray()) {
xContentBuilder.startArray(field.getName());
}
else {
if (Validator.isNull(field.getName())) {
xContentBuilder.startObject();
}
else {
xContentBuilder.startObject(field.getName());
}
}
addFields(field.getFields(), xContentBuilder);
if (field.isArray()) {
xContentBuilder.endArray();
}
else {
xContentBuilder.endObject();
}
}
protected Object translateValue(Field field, String value) {
if (!field.isNumeric()) {
return value;
}
Class<? extends Number> clazz = field.getNumericClass();
if (clazz.equals(Float.class)) {
return Float.valueOf(value);
}
else if (clazz.equals(Integer.class)) {
return Integer.valueOf(value);
}
else if (clazz.equals(Long.class)) {
return Long.valueOf(value);
}
else if (clazz.equals(Short.class)) {
return Short.valueOf(value);
}
return Double.valueOf(value);
}
}