org.appng.api.support.RequestSupportImpl Maven / Gradle / Ivy
/*
* Copyright 2011-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.appng.api.support;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.appng.api.BusinessException;
import org.appng.api.Environment;
import org.appng.api.FieldProcessor;
import org.appng.api.FieldWrapper;
import org.appng.api.MessageParam;
import org.appng.api.RequestSupport;
import org.appng.el.ExpressionEvaluator;
import org.appng.forms.RequestContainer;
import org.appng.xml.platform.Condition;
import org.appng.xml.platform.FieldDef;
import org.appng.xml.platform.MetaData;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.MessageSource;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.ClassUtils;
import lombok.extern.slf4j.Slf4j;
/**
*
* Default {@link RequestSupport} implementation
*
* @author Matthias Müller
*
*/
@Slf4j
public class RequestSupportImpl extends AdapterBase implements RequestSupport {
public RequestSupportImpl() {
}
public RequestSupportImpl(ConversionService conversionService, Environment environment,
MessageSource messageSource) {
setConversionService(conversionService);
setEnvironment(environment);
setMessageSource(messageSource);
}
public final void fillBindObject(Object instance, FieldProcessor fp, RequestContainer container,
ClassLoader classLoader) throws BusinessException {
FieldDef currentField = null;
MetaData metaData = fp.getMetaData();
String bindClassName = metaData.getBindClass();
try {
Class> bindClass = getBindClass(classLoader, bindClassName);
if (!instance.getClass().isAssignableFrom(bindClass)) {
throw new BusinessException("given object is of type '" + instance.getClass().getName()
+ "', but bindClass is '" + bindClass.getName() + "'");
}
BeanWrapper beanWrapper = new BeanWrapperImpl(instance);
for (FieldDef fieldDef : metaData.getFields()) {
if (!Boolean.TRUE.toString().equalsIgnoreCase(fieldDef.getReadonly())) {
currentField = fieldDef;
FieldWrapper fieldWrapper = new FieldWrapper(fieldDef, beanWrapper);
fieldConverter.setObject(fieldWrapper, container);
} else {
LOGGER.trace("{} is readonly!", fieldDef.getBinding());
}
}
} catch (Exception e) {
if (e instanceof BusinessException) {
throw (BusinessException) e;
}
if (null != currentField) {
throw new BusinessException("error while processing field '" + currentField.getName() + "' (type: "
+ currentField.getType() + ", binding: '" + currentField.getBinding() + "')' on bindclass '"
+ bindClassName + "'", e);
} else {
throw new BusinessException("error while creating bindobject field ", e);
}
}
}
public final Object getBindObject(FieldProcessor fp, RequestContainer container, ClassLoader classLoader)
throws BusinessException {
Object instance = getBindClassInstance(classLoader, fp);
fillBindObject(instance, fp, container, classLoader);
return instance;
}
private Object getBindClassInstance(ClassLoader classLoader, FieldProcessor fp) throws BusinessException {
String bindClassName = fp.getMetaData().getBindClass();
String errorMssg = String.format(
"could not instanciate class '%s', is it an interface or default-constructor missing?", bindClassName);
try {
Class> bindClass = getBindClass(classLoader, bindClassName);
Class> enclosingClass = bindClass.getEnclosingClass();
int modifier = bindClass.getModifiers();
if (enclosingClass == null || Modifier.isStatic(modifier)) {
return bindClass.newInstance();
} else {
if (Modifier.isPublic(modifier)) {
return bindClass.getConstructor(enclosingClass).newInstance(enclosingClass.newInstance());
} else {
throw new BusinessException("bindClass " + bindClass.getName() + " needs to be public!");
}
}
} catch (IllegalAccessException e) {
throw new BusinessException(errorMssg, e);
} catch (InstantiationException e) {
throw new BusinessException(errorMssg, e);
} catch (InvocationTargetException e) {
throw new BusinessException(errorMssg, e);
} catch (NoSuchMethodException e) {
throw new BusinessException(errorMssg, e);
}
}
private Class> getBindClass(ClassLoader classLoader, String bindClass) throws BusinessException {
if (StringUtils.isNotBlank(bindClass)) {
try {
return ClassUtils.forName(bindClass, classLoader);
} catch (ClassNotFoundException e) {
throw new BusinessException("class '" + bindClass + "' not found in classloader " + classLoader, e);
}
} else {
throw new BusinessException("bindclass is empty!");
}
}
public T convert(Object source, Class target, T defaultValue) {
T result = conversionService.convert(source, target);
if (null != result) {
return result;
}
return defaultValue;
}
public T getDefaultIfNull(T source, T defaultValue) {
if (null == source) {
return defaultValue;
}
return source;
}
public String getMessage(String key, Object... args) {
return getMessageSource().getMessage(key, args, getEnvironment().getLocale());
}
public void addErrorMessage(FieldProcessor fp, MessageParam messageParam) {
String messageKey = messageParam.getMessageKey();
if (null != messageKey) {
Object[] messageArgs = messageParam.getMessageArgs();
fp.addErrorMessage(getMessage(messageKey, messageArgs));
}
}
public void addErrorMessage(FieldProcessor fp, MessageParam messageParam, String fieldBinding) {
String messageKey = messageParam.getMessageKey();
if (null != messageKey) {
Object[] messageArgs = messageParam.getMessageArgs();
String message = getMessage(messageKey, messageArgs);
if (null != fieldBinding) {
FieldDef field = fp.getField(fieldBinding);
if (null != field) {
fp.addErrorMessage(field, message);
return;
}
}
fp.addErrorMessage(message);
}
}
public void handleException(FieldProcessor fp, Exception e) throws BusinessException {
if (e instanceof MessageParam) {
MessageParam messageParam = (MessageParam) e;
addErrorMessage(fp, messageParam);
}
if (e instanceof BusinessException) {
BusinessException businessException = (BusinessException) e;
throw businessException;
} else {
throw new BusinessException(e);
}
}
public void setPropertyValues(T source, T target, MetaData metaData) {
String bindClassName = metaData.getBindClass();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class> bindClass = getBindClass(classLoader, bindClassName);
Class extends Object> sourceClass = source.getClass();
if (!bindClass.isAssignableFrom(sourceClass)) {
throw new IllegalArgumentException("source object '" + sourceClass.getName()
+ "' is not an instance of bindClass '" + bindClassName + "'");
}
Class extends Object> targetClass = target.getClass();
if (!bindClass.isAssignableFrom(targetClass)) {
throw new IllegalArgumentException("target object '" + targetClass.getName()
+ "' is not an instance of bindClass '" + bindClassName + "'");
}
} catch (BusinessException e) {
throw new IllegalArgumentException("invalid bindclass: '" + bindClassName + "'", e);
}
BeanWrapper sourceWrapper = new BeanWrapperImpl(source);
BeanWrapper targetWrapper = new BeanWrapperImpl(target);
Map parameters = new HashMap<>();
ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator(parameters);
expressionEvaluator.setVariable(CURRENT, source);
setPropertyValues(sourceWrapper, targetWrapper, metaData, expressionEvaluator);
}
public void setPropertyValue(T source, T target, String property) {
BeanWrapper sourceWrapper = new BeanWrapperImpl(source);
BeanWrapper targetWrapper = new BeanWrapperImpl(target);
setPropertyValues(sourceWrapper, targetWrapper, property);
}
private void setPropertyValues(BeanWrapper sourceWrapper, BeanWrapper targetWrapper, MetaData metaData,
ExpressionEvaluator expressionEvaluator) {
for (FieldDef fieldDef : metaData.getFields()) {
boolean doWrite = true;
String fieldBinding = fieldDef.getBinding();
Condition condition = fieldDef.getCondition();
String expression = null;
if (null != condition) {
expression = condition.getExpression();
if (StringUtils.isNotBlank(expression)) {
doWrite = expressionEvaluator.evaluate(expression);
if (doWrite) {
LOGGER.debug("condition '{}' for property '{}' matched", expression, fieldBinding);
} else {
LOGGER.debug("condition '{}' for property '{}' did not match, skipping field", expression,
fieldBinding);
}
}
}
if (doWrite) {
setPropertyValues(sourceWrapper, targetWrapper, fieldBinding);
}
}
}
private void setPropertyValues(BeanWrapper sourceWrapper, BeanWrapper targetWrapper, String... name) {
for (String property : name) {
if (sourceWrapper.isReadableProperty(property)) {
if (targetWrapper.isWritableProperty(property)) {
Object propertyValue = sourceWrapper.getPropertyValue(property);
if (!(propertyValue instanceof Collection>)) {
LOGGER.debug("setting property '{}' of class '{}' to '{}'", property,
targetWrapper.getWrappedClass().getName(), propertyValue);
targetWrapper.setPropertyValue(property, propertyValue);
}
}
} else {
// should never ever happen
LOGGER.error(
"property '" + property + "' not readable in class '" + sourceWrapper.getWrappedClass() + "'");
}
}
}
public boolean canConvert(Class> sourceType, Class> targetType) {
return conversionService.canConvert(sourceType, targetType);
}
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
return conversionService.canConvert(sourceType, targetType);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return conversionService.convert(source, sourceType, targetType);
}
public T convert(Object source, Class target) {
return conversionService.convert(source, target);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy