package com.psddev.cms.view.servlet;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.LoggerFactory;
import com.psddev.cms.view.ViewModel;
import com.psddev.dari.util.Converter;
import com.psddev.dari.util.TypeDefinition;
public class ServletViewModelCreator extends ViewModel.DefaultCreator {
private static final Converter CONVERTER = new Converter(); static {
CONVERTER.putAllStandardFunctions();
}
private HttpServletRequest request;
public ServletViewModelCreator(HttpServletRequest request) {
this.request = request;
}
@Override
protected <M, VM extends ViewModel<? super M>> void beforeViewModelOnCreate(VM viewModel) {
updateWithRequest(viewModel);
}
private <M, VM extends ViewModel<? super M>> void updateWithRequest(VM viewModel) {
if (viewModel == null) {
return;
}
try {
TypeDefinition<? extends ViewModel> viewModelDefinition = TypeDefinition.getInstance(viewModel.getClass());
for (Map.Entry<String, List<Field>> entry : viewModelDefinition.getAllSerializableFields().entrySet()) {
Field field = entry.getValue().get(entry.getValue().size() - 1);
String fieldName = field.getName();
Object fieldValue = null;
// check for annotation processors.
for (Annotation viewModelAnnotation : field.getAnnotations()) {
Class<?> annotationClass = viewModelAnnotation.annotationType();
ServletViewRequestAnnotationProcessorClass annotation = annotationClass.getAnnotation(
ServletViewRequestAnnotationProcessorClass.class);
if (annotation != null) {
Class<? extends ServletViewRequestAnnotationProcessor<? extends Annotation>> annotationProcessorClass = annotation.value();
if (annotationProcessorClass != null) {
@SuppressWarnings("unchecked")
ServletViewRequestAnnotationProcessor<Annotation> annotationProcessor
= (ServletViewRequestAnnotationProcessor<Annotation>) TypeDefinition.getInstance(annotationProcessorClass).newInstance();
fieldValue = annotationProcessor.getValue(request, fieldName, viewModelAnnotation);
break;
}
}
}
if (fieldValue != null) {
try {
// Handle the case where the field value is a collection but the field type is not.
if (fieldValue instanceof Collection && !Collection.class.isAssignableFrom(field.getType())) {
if (!((Collection<?>) fieldValue).isEmpty()) {
// get the first value from the collection
fieldValue = ((Collection<?>) fieldValue).iterator().next();
} else {
fieldValue = null;
}
}
field.set(viewModel, CONVERTER.convert(field.getGenericType(), fieldValue));
} catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
}
} catch (RuntimeException e) {
LoggerFactory.getLogger(ServletViewModelCreator.class)
.warn("Failed to update view model of type ["
+ viewModel.getClass() + "] with all request data. Cause: " + e.getMessage(), e);
}
}
}