/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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.seasar.extension.dxo.util;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.PropertyDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
/**
* 変換ルールで指定された簡略式の評価可能な表現です。
* <p>
* 簡略式の文法を以下に示します。
* </p>
*
* <pre>
* ConversionRuleList:
* ConversionRule
* ConversionRuleList , ConversionRule
*
* ConversionRule:
* DestProperty : null
* DestProperty : SourcePropertyList
*
* SourcePropertyList:
* SourceProperty
* SourcePropertyList . SourceProperty
*
* SourceProperty:
* Identifier
*
* DestProperty:
* Identifier
* </pre>
*
* <p>
* <code>ConversionRule</code>を評価する際、 <code>SourcePathList</code>中に値が<code>null</code>のプロパティが含まれていた場合は、
* <code>null</code>が<code>ConversionRule</code>の値となります。
* </p>
*
* @author koichik
*/
public class SimpleExpression implements Expression {
/** {@link ConversionRule}のリスト */
protected LinkedList conversionRuleList = new LinkedList();
/**
* インスタンスを構築します。
*
* @param source
* 式のソース文字列
*/
public SimpleExpression() {
}
public Map evaluate(final Object source) {
final Map map = new LinkedHashMap();
for (final Iterator it = conversionRuleList.iterator(); it.hasNext();) {
final ConversionRule conversionRule = (ConversionRule) it.next();
conversionRule.evaluate(source, map);
}
return map;
}
/**
* 変換先プロパティ名を追加します。
*
* @param destProperty
* 変換先プロパティ名
*/
protected void addDestProperty(final String destProperty) {
conversionRuleList.add(new ConversionRule(destProperty));
}
/**
* 変換元プロパティを追加します。
*
* @param sourceProperty
* 変換元プロパティ
*/
protected void addSourceProperty(final String sourceProperty) {
final ConversionRule pair = (ConversionRule) conversionRuleList
.getLast();
pair.addSourceProperty(sourceProperty);
}
/**
* 変換ルールを表現します。
*/
public static class ConversionRule {
/** 変換先プロパティ名 */
protected String destProperty;
/** 変換元プロパティ名のリスト */
protected LinkedList sourcePropertyList = new LinkedList();
/**
* インスタンスを構築します。
*
* @param destProperty
* 変換先プロパティ名
*/
public ConversionRule(final String destProperty) {
this.destProperty = destProperty;
}
/**
* 変換元プロパティ名を追加します。
*
* @param sourceProperty
* 変換元プロパティ名
*/
public void addSourceProperty(final String sourceProperty) {
sourcePropertyList.addLast(sourceProperty);
}
/**
* 変換ルールを評価します。
*
* @param source
* 変換元オブジェクト
* @param dest
* 変換先の{@link Map}
*/
public void evaluate(Object source, final Map dest) {
for (final Iterator it = sourcePropertyList.iterator(); it
.hasNext();) {
final String sourceProperty = (String) it.next();
if (sourceProperty == null) {
source = null;
} else if (source instanceof Map) {
source = ((Map) source).get(sourceProperty);
} else {
final BeanDesc beanDesc = BeanDescFactory
.getBeanDesc(source.getClass());
final PropertyDesc propertyDesc = beanDesc
.getPropertyDesc(sourceProperty);
source = propertyDesc.getValue(source);
}
if (source == null) {
break;
}
}
dest.put(destProperty, source);
}
public String toString() {
final StringBuffer buf = new StringBuffer();
buf.append(destProperty).append(" : ");
boolean hasValue = false;
for (final Iterator it = sourcePropertyList.iterator(); it
.hasNext();) {
buf.append(it.next()).append(", ");
hasValue = true;
}
if (hasValue) {
buf.setLength(buf.length() - 2);
}
return new String(buf);
}
}
}