package play.modules.search.store;
import java.util.Collection;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import play.Logger;
import play.data.binding.Binder;
import play.db.jpa.Blob;
import play.db.jpa.JPABase;
import play.db.jpa.Model;
import play.exceptions.UnexpectedException;
import play.modules.search.Indexed;
/**
* Various utils handling object to index and query result to object conversion
*
* @author jfp
*/
public class ConvertionUtils {
/**
* Examines a JPABase object and creates the corresponding Lucene Document
*
* @param object to examine, expected a JPABase object
* @return the corresponding Lucene document
* @throws Exception
*/
public static Document toDocument(Object object) throws Exception {
Indexed indexed = object.getClass().getAnnotation(Indexed.class);
if (indexed == null)
return null;
if (!(object instanceof JPABase))
return null;
JPABase jpaBase = (JPABase) object;
Document document = new Document();
document.add(new Field("_docID", getIdValueFor(jpaBase) + "", Field.Store.YES, Field.Index.NOT_ANALYZED));
StringBuffer allValue = new StringBuffer();
for (java.lang.reflect.Field field : object.getClass().getFields()) {
play.modules.search.Field index = field.getAnnotation(play.modules.search.Field.class);
if (index == null)
continue;
if (field.getType().isArray())
continue;
if (Collection.class.isAssignableFrom(field.getType()))
continue;
String name = field.getName();
String value = null;
if (JPABase.class.isAssignableFrom(field.getType()) && !(index.joinField().length() == 0)) {
JPABase joinObject = (JPABase ) field.get(object);
for (java.lang.reflect.Field joinField : joinObject.getClass().getFields()) {
if (joinField.getName().equals(index.joinField())) {
name = joinField.getName();
value = valueOf(joinObject, joinField);
}
}
} else {
value = valueOf(object, field);
}
if (value == null)
continue;
document.add(new Field(name, value, index.stored() ? Field.Store.YES : Field.Store.NO,
index.tokenize() ? Field.Index.ANALYZED : Field.Index.NOT_ANALYZED));
if (index.tokenize() && index.sortable()) {
document.add(new Field(name + "_untokenized", value, index.stored() ? Field.Store.YES : Field.Store.NO,
Field.Index.NOT_ANALYZED));
}
allValue.append(value).append(' ');
}
document.add(new Field("allfield", allValue.toString(), Field.Store.NO, Field.Index.ANALYZED));
return document;
}
public static String valueOf(Object object, java.lang.reflect.Field field) throws Exception {
if (field.getType().equals(String.class)) {
return (String ) field.get(object);
}
if (field.getType().equals(Blob.class) && field.get(object) != null) {
return FileExtractor.getText((Blob) field.get(object));
}
Object o = field.get(object);
if (field.isAnnotationPresent(ManyToOne.class) && o instanceof JPABase) {
return "" + getIdValueFor((JPABase ) o);
}
return "" + field.get(object);
}
/**
* Looks for the type of the id fiels on the JPABase target class and use
* play's binder to retrieve the corresponding object used to build JPA load
* query
*
* @param clazz JPABase target class
* @param indexValue String value of the id, taken from index
* @return Object id expected to build query
*/
public static Object getIdValueFromIndex(Class<?> clazz, String indexValue) {
java.lang.reflect.Field field = getIdField(clazz);
Class<?> parameter = field.getType();
try {
return Binder.directBind(indexValue, parameter);
} catch (Exception e) {
throw new UnexpectedException("Could not convert the ID from index to corresponding type", e);
}
}
/**
* Find a ID field on the JPABase target class
*
* @param clazz JPABase target class
* @return corresponding field
*/
public static java.lang.reflect.Field getIdField(Class<?> clazz) {
for (java.lang.reflect.Field field : clazz.getFields()) {
if (field.getAnnotation(Id.class) != null) {
return field;
}
}
throw new RuntimeException("Your class " + clazz.getName()
+ " is annotated with javax.persistence.Id but the field Id was not found");
}
/**
* Lookups the id field, being a Long id for Model and an annotated field @Id
* for JPABase and returns the field value.
*
* @param jpaBase is a Play! Framework that supports JPA
* @return the field value (a Long or a String for UUID)
*/
public static Object getIdValueFor(JPABase jpaBase) {
if (jpaBase instanceof Model) {
return ((Model ) jpaBase).id;
}
java.lang.reflect.Field field = getIdField(jpaBase.getClass());
Object val = null;
try {
val = field.get(jpaBase);
} catch (IllegalAccessException e) {
Logger.error("Unable to read the field value of a field annotated with @Id " + field.getName() + " due to "
+ e.getMessage(), e);
}
return val;
}
public static boolean isForcedUntokenized(Class<?> clazz, String fieldName) {
try {
java.lang.reflect.Field field = clazz.getField(fieldName);
play.modules.search.Field index = field.getAnnotation(play.modules.search.Field.class);
return index.tokenize() && index.sortable();
} catch (Exception e) {
Logger.error("%s", e.getCause());
}
return false;
}
}