/*
* 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.factory;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.PropertyDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;
import org.seasar.framework.container.AccessTypeDef;
import org.seasar.framework.container.AutoBindingDef;
import org.seasar.framework.container.BindingTypeDef;
import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.DestroyMethodDef;
import org.seasar.framework.container.InitMethodDef;
import org.seasar.framework.container.InstanceDef;
import org.seasar.framework.container.PropertyDef;
import org.seasar.framework.container.assembler.AccessTypeDefFactory;
import org.seasar.framework.container.assembler.AutoBindingDefFactory;
import org.seasar.framework.container.assembler.BindingTypeDefFactory;
import org.seasar.framework.container.deployer.InstanceDefFactory;
import org.seasar.framework.container.impl.ComponentDefImpl;
import org.seasar.framework.container.impl.PropertyDefImpl;
import org.seasar.framework.container.ognl.OgnlExpression;
import org.seasar.framework.util.ClassUtil;
import org.seasar.framework.util.StringUtil;
/**
* AnnotationHandlerの抽象クラスです。
* <p>
* このクラスでは、主にクラス、メソッド、フィールドに書かれたアノーテションを取得します。
* アノーテションから、コンポーネントに対しての各定義の作成はサブクラスで行います。
* </p>
*
* @author vestige
*/
public abstract class AbstractAnnotationHandler implements AnnotationHandler {
/**
* COMPONENTアノテーションを表す定数名です。
*/
protected static final String COMPONENT = "COMPONENT";
/**
* COMPONENTアノテーションのname属性「コンポーネント名」を表すキーです。
*/
protected static final String NAME = "name";
/**
* COMPONENTアノテーションのinstance属性「インスタンス定義」を表すキーです。
*/
protected static final String INSTANCE = "instance";
/**
* COMPONENTアノテーションのautoBinding属性「自動バインディング定義」を表すキーです。
*/
protected static final String AUTO_BINDING = "autoBinding";
/**
* Bindingアノテーションとして識別するための定数です。
*/
protected static final String BINDING_SUFFIX = "_BINDING";
/**
* BindingアノテーションのbindingType属性「バインディングタイプ」を表すキーです。
*/
protected static final String BINDING_TYPE = "bindingType";
/**
* COMPONENTアノテーションのexternalBinding属性「外部バインディング定義」を表すキーです。
*/
protected static final String EXTERNAL_BINDING = "externalBinding";
/**
* 各アノテーション内のvalue属性「VALUE」を表すキーです。
*/
protected static final String VALUE = "value";
/**
* ASPECTアノテーションを表す定数名です。
*/
protected static final String ASPECT = "ASPECT";
/**
* InterTypeアノテーションを表す定数名です。
*/
protected static final String INTER_TYPE = "INTER_TYPE";
/**
* InitMethodアノテーションを表す定数名です。
*/
protected static final String INIT_METHOD = "INIT_METHOD";
/**
* DestroyMethodアノテーションを表す定数名です。
*/
protected static final String DESTROY_METHOD = "DESTROY_METHOD";
/**
* ASPECTアノテーションのinterceptor属性「インターセプター定義」を表すキーです。
*/
protected static final String INTERCEPTOR = "interceptor";
/**
* ASPECTアノテーションのpointcut属性「ポイントカット定義」を表すキーです。
*/
protected static final String POINTCUT = "pointcut";
public ComponentDef createComponentDef(String className,
InstanceDef instanceDef) {
return createComponentDef(ClassUtil.forName(className), instanceDef);
}
public ComponentDef createComponentDef(String className,
InstanceDef instanceDef, AutoBindingDef autoBindingDef) {
return createComponentDef(ClassUtil.forName(className), instanceDef,
autoBindingDef);
}
public ComponentDef createComponentDef(String className,
InstanceDef instanceDef, AutoBindingDef autoBindingDef,
boolean externalBinding) {
return createComponentDef(ClassUtil.forName(className), instanceDef,
autoBindingDef, externalBinding);
}
public ComponentDef createComponentDef(Class componentClass,
InstanceDef instanceDef) {
return createComponentDef(componentClass, instanceDef, null);
}
public ComponentDef createComponentDef(Class componentClass,
InstanceDef instanceDef, AutoBindingDef autoBindingDef) {
return createComponentDef(componentClass, instanceDef, autoBindingDef,
false);
}
public void appendDI(ComponentDef componentDef) {
BeanDesc beanDesc = BeanDescFactory.getBeanDesc(componentDef
.getComponentClass());
for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) {
PropertyDesc pd = beanDesc.getPropertyDesc(i);
if (!pd.isWritable()) {
continue;
}
PropertyDef propDef = createPropertyDef(beanDesc, pd);
if (propDef == null) {
continue;
}
componentDef.addPropertyDef(propDef);
}
for (int i = 0; i < beanDesc.getFieldSize(); ++i) {
Field field = beanDesc.getField(i);
if (componentDef.hasPropertyDef(field.getName())) {
continue;
}
if (!isFieldInjectionTarget(field)) {
continue;
}
PropertyDef propDef = createPropertyDef(beanDesc, field);
if (propDef == null) {
continue;
}
componentDef.addPropertyDef(propDef);
}
}
/**
* インスタンス定義を返します。
* <p>
* 指定した名前のインスタンス定義が存在しない場合、デフォルトのインスタンス定義を返します。
* </p>
*
* @param name
* インスタンス定義の種類
* @param defaultInstanceDef
* デフォルトのインスタンス定義(singleton)
* @return インスタンス定義
*/
protected InstanceDef getInstanceDef(String name,
InstanceDef defaultInstanceDef) {
InstanceDef instanceDef = getInstanceDef(name);
if (instanceDef != null) {
return instanceDef;
}
return defaultInstanceDef;
}
/**
* インスタンス定義を返します。
*
* @param name
* インスタンス定義の種類
* @return インスタンス定義
*/
protected InstanceDef getInstanceDef(String name) {
if (StringUtil.isEmpty(name)) {
return null;
}
return InstanceDefFactory.getInstanceDef(name);
}
/**
* 自動バインディング定義を返します。
*
* @param name
* 自動バインディング定義の種類
* @return 自動バインディング定義
*/
protected AutoBindingDef getAutoBindingDef(String name) {
if (StringUtil.isEmpty(name)) {
return null;
}
return AutoBindingDefFactory.getAutoBindingDef(name);
}
/**
* 指定したコンポーネントクラスからコンポーネント定義を作成します。
* <p>
* 以下の設定がある場合はおのおのコンポーネント定義に設定します。
* <ul>
* <li>コンポーネント名
* <li>インスタンス定義
* <li>自動バインディング定義
* <li>外部バインディングの有無
* </ul>
* </p>
*
* @param componentClass
* コンポーネントクラス
* @param name
* コンポーネント名
* @param instanceDef
* インスタンス定義
* @param autoBindingDef
* 自動バインディング定義
* @param externalBinding
* 外部バインディングの有無
* @return コンポーネント定義
*/
protected ComponentDef createComponentDef(Class componentClass,
String name, InstanceDef instanceDef,
AutoBindingDef autoBindingDef, boolean externalBinding) {
ComponentDef componentDef = new ComponentDefImpl(componentClass);
if (!StringUtil.isEmpty(name)) {
componentDef.setComponentName(name);
}
if (instanceDef != null) {
componentDef.setInstanceDef(instanceDef);
}
if (autoBindingDef != null) {
componentDef.setAutoBindingDef(autoBindingDef);
}
componentDef.setExternalBinding(externalBinding);
return componentDef;
}
/**
* プロパティ定義を作成します。
*
* @param propertyName
* プロパティ名
* @param expression
* 引数定義の値となる式
* @param bindingTypeName
* バインディングタイプ定義
* @param accessTypeName
* アクセスタイプ定義
* @return プロパティ定義
*/
protected PropertyDef createPropertyDef(String propertyName,
String expression, String bindingTypeName, String accessTypeName) {
PropertyDef propertyDef = new PropertyDefImpl(propertyName);
if (!StringUtil.isEmpty(bindingTypeName)) {
BindingTypeDef bindingTypeDef = BindingTypeDefFactory
.getBindingTypeDef(bindingTypeName);
propertyDef.setBindingTypeDef(bindingTypeDef);
}
if (!StringUtil.isEmpty(accessTypeName)) {
AccessTypeDef accessTypeDef = AccessTypeDefFactory
.getAccessTypeDef(accessTypeName);
propertyDef.setAccessTypeDef(accessTypeDef);
}
if (!StringUtil.isEmpty(expression)) {
propertyDef.setExpression(new OgnlExpression(expression));
}
return propertyDef;
}
public boolean isInitMethodRegisterable(ComponentDef cd, String methodName) {
if (StringUtil.isEmpty(methodName)) {
return false;
}
for (int i = 0; i < cd.getInitMethodDefSize(); ++i) {
InitMethodDef other = cd.getInitMethodDef(i);
if (methodName.equals(other.getMethodName())
&& other.getArgDefSize() == 0) {
return false;
}
}
return true;
}
public boolean isDestroyMethodRegisterable(ComponentDef cd,
String methodName) {
if (StringUtil.isEmpty(methodName)) {
return false;
}
for (int i = 0; i < cd.getDestroyMethodDefSize(); ++i) {
DestroyMethodDef other = cd.getDestroyMethodDef(i);
if (methodName.equals(other.getMethodName())
&& other.getArgDefSize() == 0) {
return false;
}
}
return true;
}
/**
* 指定したフィールドがインジェクション可能かどうかの判定を行います。
* <P>
* <code>static</code>または、<code>final</code>でない場合はインジェクションが可能になります。
* </p>
*
* @param field
* フィールド
* @return フィールドが<code>static</code>、<code>final</code>でない場合は<code>true</code>、そうでない場合は<code>false</code>を返す。
*/
protected boolean isFieldInjectionTarget(Field field) {
return !Modifier.isStatic(field.getModifiers())
&& !Modifier.isFinal(field.getModifiers());
}
}