/*
* 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.creator;
import java.lang.reflect.Modifier;
import org.seasar.framework.container.AutoBindingDef;
import org.seasar.framework.container.ComponentCreator;
import org.seasar.framework.container.ComponentCustomizer;
import org.seasar.framework.container.ComponentDef;
import org.seasar.framework.container.InstanceDef;
import org.seasar.framework.container.factory.AnnotationHandler;
import org.seasar.framework.container.factory.AnnotationHandlerFactory;
import org.seasar.framework.convention.NamingConvention;
import org.seasar.framework.exception.EmptyRuntimeException;
/**
* {@link org.seasar.framework.container.ComponentCreator}の汎用的な実装です。
* <p>
* このクラスによって作られるコンポーネント定義に含める{@link InstanceDef インスタンス定義}、
* {@link AutoBindingDef 自動バインディング定義}、
* {@link org.seasar.framework.container.ExternalContext 外部バインディング}の有効/無効が設定できます。
* インターフェースや抽象クラスをコンポーネント定義作成の対象とする場合、
* AOP(AspectCustomzier)で実装クラスが作られるようにする必要があります。
* </p>
* <p>
* このクラスがコンポーネント定義を作成するべきかどうかは、 コンポーネント名のサフィックスで判断しています。 コンポーネント名が{@link #setNameSuffix(String)}で設定したサフィックスに該当した場合のみ、
* コンポーネント定義を作成します。
* </p>
*
* @author higa
* @author jundu
*/
public class ComponentCreatorImpl implements ComponentCreator {
private NamingConvention namingConvention;
/**
* プロパティ<code>instanceDef</code>のためのBindingアノテーションの定義です。
*/
public static final String instanceDef_BINDING = "bindingType=may";
private InstanceDef instanceDef;
/**
* プロパティ<code>autoBindingDef</code>のためのBindingアノテーションの定義です。
*/
public static final String autoBindingDef_BINDING = "bindingType=may";
private AutoBindingDef autoBindingDef;
/**
* プロパティ<code>externalBinding</code>のためのBindingアノテーションの定義です。
*/
public static final String externalBinding_BINDING = "bindingType=may";
private boolean externalBinding = false;
/**
* プロパティ<code>enableInterface</code>のためのBindingアノテーションの定義です。
*/
public static final String enableInterface_BINDING = "bindingType=may";
private boolean enableInterface = false;
/**
* プロパティ<code>enableAbstract</code>のためのBindingアノテーションの定義です。
*/
public static final String enableAbstract_BINDING = "bindingType=may";
private boolean enableAbstract = false;
private String nameSuffix;
private ComponentCustomizer customizer;
/**
* 指定された{@link NamingConvention 命名規約}に従った<code>ComponentCreatorImpl</code>を構築します。
*
* @param namingConvention
* 命名規約
*/
public ComponentCreatorImpl(NamingConvention namingConvention) {
if (namingConvention == null) {
throw new EmptyRuntimeException("namingConvetion");
}
this.namingConvention = namingConvention;
}
/**
* {@link NamingConvention 命名規約}を返します。
*
* @return 命名規約
*/
public NamingConvention getNamingConvention() {
return namingConvention;
}
/**
* {@link InstanceDef インスタンス定義}を返します。
*
* @return インスタンス定義
*/
public InstanceDef getInstanceDef() {
return instanceDef;
}
/**
* {@link InstanceDef インスタンス定義}を設定します。
*
* @param instanceDef
* インスタンス定義
*/
public void setInstanceDef(InstanceDef instanceDef) {
this.instanceDef = instanceDef;
}
/**
* {@link AutoBindingDef 自動バインディング定義}を返します。
*
* @return 自動バインディング定義
*/
public AutoBindingDef getAutoBindingDef() {
return autoBindingDef;
}
/**
* {@link AutoBindingDef 自動バインディング定義}を設定します。
*
* @param autoBindingDef
* 自動バインディング定義
*/
public void setAutoBindingDef(AutoBindingDef autoBindingDef) {
this.autoBindingDef = autoBindingDef;
}
/**
* {@link org.seasar.framework.container.ExternalContext 外部バインディング}が有効かどうかを返します。
*
* @return 外部バインディングが有効な場合<code>true</code>、 それ以外の場合<code>false</code>を返す
*/
public boolean isExternalBinding() {
return externalBinding;
}
/**
* 外{@link org.seasar.framework.container.ExternalContext 外部バインディング}を有効にするかどうかを設定します。
*
* @param externalBinding
* 外部バインディングを有効にする場合は<code>true</code>、 それ以外の場合<code>false</code>を指定する
*/
public void setExternalBinding(boolean externalBinding) {
this.externalBinding = externalBinding;
}
/**
* インターフェースを対象にするかどうかを返します。
*
* @return インターフェースを対象にする場合<code>true</code>、 それ以外の場合<code>false</code>を返す
*/
public boolean isEnableInterface() {
return enableInterface;
}
/**
* インターフェースを対象にするかどうかを設定します。
*
* @param enableInterface
* インターフェースを対象にする場合<code>true</code>、 それ以外の場合<code>false</code>を指定する
*/
public void setEnableInterface(boolean enableInterface) {
this.enableInterface = enableInterface;
}
/**
* 抽象クラスを対象にするかどうかを返します。
*
* @return 抽象クラスを対象にする場合<code>true</code>、 それ以外の場合<code>false</code>を返す
*/
public boolean isEnableAbstract() {
return enableAbstract;
}
/**
* 抽象クラスを対象にするかどうかを設定します。
*
* @param enableAbstract
* 抽象クラスを対象とする場合<code>true</code>、 それ以外の場合<code>false</code>を指定する
*/
public void setEnableAbstract(boolean enableAbstract) {
this.enableAbstract = enableAbstract;
}
/**
* コンポーネント名のサフィックスを返します。
*
* @return 名前のサフィックス
*/
public String getNameSuffix() {
return nameSuffix;
}
/**
* コンポーネント名のサフィックスを設定します。
*
* @param nameSuffix
* 名前のサフィックス
*/
public void setNameSuffix(String nameSuffix) {
this.nameSuffix = nameSuffix;
}
/**
* {@link ComponentCustomizer コンポーネント定義カスタマイザ}を返します。
*
* @return コンポーネント定義カスタマイザ
*/
protected ComponentCustomizer getCustomizer() {
return customizer;
}
/**
* {@link ComponentCustomizer コンポーネント定義カスタマイザ}を設定します。
*
* @param customizer
* コンポーネント定義カスタマイザ
*/
protected void setCustomizer(ComponentCustomizer customizer) {
this.customizer = customizer;
}
public ComponentDef createComponentDef(Class componentClass) {
if (!namingConvention.isTargetClassName(componentClass.getName(),
nameSuffix)) {
return null;
}
Class targetClass = namingConvention.toCompleteClass(componentClass);
if (targetClass.isInterface()) {
if (!isEnableInterface()) {
return null;
}
} else if (Modifier.isAbstract(targetClass.getModifiers())) {
if (!isEnableAbstract()) {
return null;
}
}
AnnotationHandler handler = AnnotationHandlerFactory
.getAnnotationHandler();
ComponentDef cd = handler.createComponentDef(targetClass, instanceDef,
autoBindingDef, externalBinding);
if (cd.getComponentName() == null) {
cd.setComponentName(namingConvention
.fromClassNameToComponentName(targetClass.getName()));
}
handler.appendDI(cd);
customize(cd);
handler.appendInitMethod(cd);
handler.appendDestroyMethod(cd);
handler.appendAspect(cd);
handler.appendInterType(cd);
return cd;
}
public ComponentDef createComponentDef(String componentName) {
if (!isTargetComponentName(componentName)) {
return null;
}
Class componentClass = namingConvention
.fromComponentNameToClass(componentName);
if (componentClass == null) {
return null;
}
return createComponentDef(componentClass);
}
/**
* 指定されたコンポーネント名が、 対象となるコンポーネント名かどうかを返します。
*
* @param componentName
* コンポーネント名
* @return 対象となるコンポーネント名の場合<code>true</code>、 それ以外の場合<code>false</code>
*/
public boolean isTargetComponentName(String componentName) {
return componentName.endsWith(nameSuffix);
}
/**
* 指定された{@link ComponentDef コンポーネント定義}を、
* {@link ComponentCustomizer コンポーネント定義カスタマイザ}を使ってカスタマイズします。
*
* @param componentDef
* コンポーネント定義
*/
protected void customize(ComponentDef componentDef) {
if (customizer != null) {
customizer.customize(componentDef);
}
}
}