/* * 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.framework.container.assembler; import java.lang.reflect.Field; import org.seasar.framework.beans.IllegalPropertyRuntimeException; import org.seasar.framework.beans.PropertyDesc; import org.seasar.framework.container.BindingTypeDef; import org.seasar.framework.container.ComponentDef; import org.seasar.framework.container.ContainerConstants; import org.seasar.framework.container.PropertyDef; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.util.BindingUtil; import org.seasar.framework.util.FieldUtil; import org.seasar.framework.util.StringUtil; /** * バインディングタイプ定義の抽象クラスです。 * * @author higa * */ public abstract class AbstractBindingTypeDef implements BindingTypeDef { private String name; /** * {@link AbstractBindingTypeDef}を作成します。 * * @param name */ protected AbstractBindingTypeDef(String name) { this.name = name; } public String getName() { return name; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof BindingTypeDef)) { return false; } BindingTypeDef other = (BindingTypeDef) o; return name == null ? other.getName() == null : name.equals(other .getName()); } public int hashCode() { return name == null ? 0 : name.hashCode(); } public void bind(ComponentDef componentDef, PropertyDef propertyDef, PropertyDesc propertyDesc, Object component) { if (propertyDef != null && propertyDef.isValueGettable()) { if (propertyDesc != null && propertyDesc.isWritable()) { bindManual(componentDef, propertyDef, propertyDesc, component); } } else { if (propertyDesc != null && propertyDesc.isWritable()) { doBind(componentDef, propertyDesc, component); } } } public void bind(ComponentDef componentDef, PropertyDef propertyDef, Field field, Object component) { if (propertyDef != null && propertyDef.isValueGettable()) { if (field != null) { bindManual(componentDef, propertyDef, field, component); } } else { if (propertyDef != null && field != null) { doBind(componentDef, field, component); } } } /** * 明示的な設定にもとづいてオブジェクトを結び付けます。 * * @param componentDef * @param propertyDef * @param field * @param component * @see #getValue(ComponentDef, PropertyDef, Object) * @see #setValue(ComponentDef, Field, Object, Object) */ protected void bindManual(ComponentDef componentDef, PropertyDef propertyDef, Field field, Object component) { Object value = getValue(componentDef, propertyDef, component); setValue(componentDef, field, component, value); } /** * 明示的な設定にもとづいてオブジェクトを結び付けます。 * * @param componentDef * @param propertyDef * @param propertyDesc * @param component * @see #getValue(ComponentDef, PropertyDef, Object) * @see #setValue(ComponentDef, PropertyDesc, Object, Object) */ protected void bindManual(ComponentDef componentDef, PropertyDef propertyDef, PropertyDesc propertyDesc, Object component) { Object value = getValue(componentDef, propertyDef, component); setValue(componentDef, propertyDesc, component, value); } /** * 自動的にオブジェクトを結び付けます。 * * @param componentDef * @param field * @param component * @return オブジェクトを結び付けたかどうか * @see #getValue(ComponentDef, Object, Object, String) * @see #setValue(ComponentDef, Field, Object, Object) */ protected boolean bindAuto(ComponentDef componentDef, Field field, Object component) { S2Container container = componentDef.getContainer(); String propName = field.getName(); Class propType = field.getType(); if (container.hasComponentDef(propType)) { ComponentDef cd = container.getComponentDef(propType); if (isAutoBindable(propName, propType, cd)) { Object value = getValue(componentDef, propType, component, propName); setValue(componentDef, field, component, value); return true; } } if (container.hasComponentDef(propName)) { Object value = getValue(componentDef, propName, component, propName); if (propType.isInstance(value)) { setValue(componentDef, field, component, value); return true; } } if (BindingUtil.isAutoBindable(propType)) { if (container.hasComponentDef(propType)) { Object value = getValue(componentDef, propType, component, propName); setValue(componentDef, field, component, value); return true; } if (propType.isAssignableFrom(ComponentDef.class)) { setValue(componentDef, field, component, componentDef); return true; } } if (BindingUtil.isAutoBindableArray(propType)) { Class clazz = propType.getComponentType(); Object[] values = container.findAllComponents(clazz); if (values.length > 0) { setValue(componentDef, field, component, values); return true; } } return false; } /** * 自動的にオブジェクトを結び付けます。 * * @param componentDef * @param propertyDesc * @param component * @return オブジェクトを結び付けたかどうか */ protected boolean bindAuto(ComponentDef componentDef, PropertyDesc propertyDesc, Object component) { S2Container container = componentDef.getContainer(); String propName = propertyDesc.getPropertyName(); Class propType = propertyDesc.getPropertyType(); if (container.hasComponentDef(propType)) { ComponentDef cd = container.getComponentDef(propType); if (isAutoBindable(propName, propType, cd)) { Object value = getValue(componentDef, propType, component, propName); setValue(componentDef, propertyDesc, component, value); return true; } } if (container.hasComponentDef(propName)) { Object value = getValue(componentDef, propName, component, propName); if (propType.isInstance(value)) { setValue(componentDef, propertyDesc, component, value); return true; } } if (BindingUtil.isAutoBindable(propType)) { if (container.hasComponentDef(propType)) { Object value = getValue(componentDef, propType, component, propName); setValue(componentDef, propertyDesc, component, value); return true; } if (propType.isAssignableFrom(ComponentDef.class)) { setValue(componentDef, propertyDesc, component, componentDef); return true; } } if (BindingUtil.isAutoBindableArray(propType)) { Class clazz = propType.getComponentType(); Object[] values = container.findAllComponents(clazz); if (values.length > 0) { setValue(componentDef, propertyDesc, component, values); return true; } } return false; } /** * プロパティにコンポーネントを自動バインディング可能なら<code>true</code>を返します。 * * @param propertyName * プロパティ名 * @param propertyType * プロパティの型 * @param cd * コンポーネント定義 * @return プロパティにコンポーネントを自動バインディング可能なら<code>true</code> */ protected boolean isAutoBindable(final String propertyName, final Class propertyType, final ComponentDef cd) { return cd.getComponentName() != null && (cd.getComponentName().equalsIgnoreCase(propertyName) || StringUtil .endsWithIgnoreCase(cd.getComponentName(), ContainerConstants.PACKAGE_SEP + propertyName)); } /** * プロパティの値を返します。 * * @param componentDef * @param propertyDef * @param component * @return プロパティの値 * @throws IllegalPropertyRuntimeException * {@link RuntimeException}が発生した場合 */ protected Object getValue(ComponentDef componentDef, PropertyDef propertyDef, Object component) throws IllegalPropertyRuntimeException { try { return propertyDef.getValue(); } catch (RuntimeException cause) { throw new IllegalPropertyRuntimeException(BindingUtil .getComponentClass(componentDef, component), propertyDef .getPropertyName(), cause); } } /** * コンポーネントを返します。 * * @param componentDef * @param key * @param component * @param propertyName * @return コンポーネント * @throws IllegalPropertyRuntimeException * {@link RuntimeException}が発生した場合 */ protected Object getValue(ComponentDef componentDef, Object key, Object component, String propertyName) throws IllegalPropertyRuntimeException { try { return componentDef.getContainer().getComponent(key); } catch (RuntimeException cause) { throw new IllegalPropertyRuntimeException(BindingUtil .getComponentClass(componentDef, component), propertyName, cause); } } /** * プロパティに値を設定します。 * * @param componentDef * @param propertyDesc * @param component * @param value * @throws IllegalPropertyRuntimeException * {@link NumberFormatException}が発生した場合 */ protected void setValue(ComponentDef componentDef, PropertyDesc propertyDesc, Object component, Object value) throws IllegalPropertyRuntimeException { if (value == null) { return; } try { propertyDesc.setValue(component, value); } catch (NumberFormatException ex) { throw new IllegalPropertyRuntimeException(componentDef .getComponentClass(), propertyDesc.getPropertyName(), ex); } } /** * {@link Field}に値を設定します。 * * @param componentDef * @param field * @param component * @param value * @throws IllegalPropertyRuntimeException * {@link NumberFormatException}が発生した場合 */ protected void setValue(ComponentDef componentDef, Field field, Object component, Object value) throws IllegalPropertyRuntimeException { if (value == null) { return; } try { FieldUtil.set(field, component, value); } catch (NumberFormatException ex) { throw new IllegalPropertyRuntimeException(componentDef .getComponentClass(), field.getName(), ex); } } /** * オブジェクトを結びつけるためのメソッドです。 * * @param componentDef * @param propertyDesc * @param component */ protected abstract void doBind(ComponentDef componentDef, PropertyDesc propertyDesc, Object component); /** * オブジェクトを結びつけるためのメソッドです。 * * @param componentDef * @param field * @param component */ protected abstract void doBind(ComponentDef componentDef, Field field, Object component); }