/*
* Copyright 2012 astamuse company,Ltd.
*
* 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 com.astamuse.asta4d.data;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.astamuse.asta4d.Configuration;
import com.astamuse.asta4d.Context;
import com.astamuse.asta4d.data.convertor.DataValueConvertor;
import com.astamuse.asta4d.data.convertor.UnsupportedValueException;
import com.astamuse.asta4d.util.i18n.I18nMessageHelper;
/**
* A default implementation of {@link ContextDataFinder}. It will search data in a given order (if scope is not specified) and try to apply
* predefined {@link ContextDataFinder} list to convert data to appropriate type.
*
* @author e-ryu
*
*/
public class DefaultContextDataFinder implements ContextDataFinder {
private final static String ByTypeScope = DefaultContextDataFinder.class.getName() + "#findByType";
private List<String> dataSearchScopeOrder = getDefaultScopeOrder();
private final static List<String> getDefaultScopeOrder() {
List<String> list = new ArrayList<>();
list.add(Context.SCOPE_ATTR);
list.add(Context.SCOPE_DEFAULT);
list.add(Context.SCOPE_GLOBAL);
return list;
}
public List<String> getDataSearchScopeOrder() {
return dataSearchScopeOrder;
}
public void setDataSearchScopeOrder(List<String> dataSearchScopeOrder) {
this.dataSearchScopeOrder = dataSearchScopeOrder;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public ContextDataHolder findDataInContext(Context context, String scope, String name, Class<?> targetType)
throws DataOperationException {
ContextDataHolder dataHolder = findByType(context, scope, name, targetType);
if (dataHolder != null) {
return dataHolder;
}
if (StringUtils.isEmpty(scope)) {
dataHolder = findDataByScopeOrder(context, 0, name);
} else {
dataHolder = context.getDataHolder(scope, name);
}
if (dataHolder == null) {
return null;
}
Object foundData = dataHolder.getValue();
Object transformedData = null;
UnsupportedValueException usve = null;
Class<?> srcType = new TypeInfo(foundData.getClass()).getType();
if (targetType.isAssignableFrom(srcType)) {
transformedData = foundData;
} else if (srcType.isArray() && targetType.isAssignableFrom(srcType.getComponentType())) {
transformedData = Array.get(foundData, 0);
} else if (targetType.isArray() && targetType.getComponentType().isAssignableFrom(srcType)) {
Object array = Array.newInstance(srcType, 1);
Array.set(array, 0, foundData);
transformedData = array;
} else {
try {
transformedData = Configuration.getConfiguration().getDataTypeTransformer().transform(srcType, targetType, foundData);
} catch (UnsupportedValueException ex) {
usve = ex;
}
}
if (usve == null) {
dataHolder.setData(dataHolder.getName(), dataHolder.getScope(), foundData, transformedData);
} else {
dataHolder.setData(dataHolder.getName(), InjectUtil.ContextDataTypeUnMatchScope, foundData, transformedData);
}
return dataHolder;
}
@SuppressWarnings("rawtypes")
private ContextDataHolder findByType(Context context, String scope, String name, Class<?> targetType) {
if (Context.class.isAssignableFrom(targetType)) {
return new ContextDataHolder<>(Context.class.getName(), ByTypeScope, context);
}
if (I18nMessageHelper.class.isAssignableFrom(targetType)) {
I18nMessageHelper helper = Configuration.getConfiguration().getI18nMessageHelper();
return new ContextDataHolder<>(helper.getClass().getName(), ByTypeScope, helper);
} else {
return null;
}
}
@SuppressWarnings("rawtypes")
private ContextDataHolder findDataByScopeOrder(Context context, int scopeIndex, String name) {
if (scopeIndex >= dataSearchScopeOrder.size()) {
return null;
} else {
String searchScope = dataSearchScopeOrder.get(scopeIndex);
ContextDataHolder<?> holder = context.getDataHolder(searchScope, name);
if (holder == null) {
holder = findDataByScopeOrder(context, scopeIndex + 1, name);
}
return holder;
}
}
private Method findConvertMethod(DataValueConvertor<?, ?> convertor) {
Method[] methods = convertor.getClass().getMethods();
Method rtnMethod = null;
for (Method m : methods) {
if (m.getName().equals("convert") && !m.isBridge()) {
rtnMethod = m;
break;
}
}
return rtnMethod;
}
}