/* * 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); } } }