/*
* Copyright 2008-2010 the T2 Project ant 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.t2framework.confeito.adapter;
import java.io.Externalizable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.t2framework.confeito.exception.ContainerAdapterStartupException;
import org.t2framework.confeito.handler.ExceptionHandler;
import org.t2framework.confeito.handler.GlobalExceptionHandler;
import org.t2framework.confeito.internal.ConfigurationUtil;
import org.t2framework.confeito.model.Component;
import org.t2framework.confeito.util.Assertion;
import org.t2framework.confeito.util.Reflections.ClassUtil;
/**
*
* <#if locale="en">
* <p>
* Simple {@link ContainerAdapter} implementation. This class is expected to use
* when you absolutely do not need DI container.
*
* With {@link SimpleContainerAdapter}, you can just use T2 without any other
* container framework.
* </p>
* <#else>
* <p>
* シンプルな {@link ContainerAdapter} 実装です.このクラスは、DIコンテナを使わない場合に使用します.
* {@link SimpleContainerAdapter}を使用することで、T2をDIコンテナなしで動作させることが出来ます.
* </p>
* </#if>
*
* @author shot
*
*/
public class SimpleContainerAdapter extends
AbstractContainerAdapter<Map<Class<?>, Object>> {
private List<Class<?>> unacceptableClasses = new ArrayList<Class<?>>();
{
unacceptableClasses.add(Cloneable.class);
unacceptableClasses.add(Comparable.class);
unacceptableClasses.add(Serializable.class);
unacceptableClasses.add(Externalizable.class);
}
/**
* <#if locale="en">
* <p>
* The container for managing objects.
* </p>
* <#else>
* <p>
* シンプルなコンテナオブジェクトです.
* </p>
* </#if>
*/
protected Map<Class<?>, Object> container;
/**
* <#if locale="en">
* <p>
* Construct SimpleContainerAdapter.
* </p>
* <#else>
* <p>
* SimpleContainerAdapterを構築します.
* </p>
* </#if>
*/
public SimpleContainerAdapter() {
setEagerLoad(true);
}
/**
* {@inheritDoc}
*/
@Override
public void init() {
this.container = Collections
.synchronizedMap(new LinkedHashMap<Class<?>, Object>());
for (Class<?> extensionClass : ConfigurationUtil
.getExtensionClasses(config)) {
register(extensionClass);
}
}
/**
* {@inheritDoc}
*/
@Override
public void init(String configPath) {
init();
}
/**
* {@inheritDoc} <#if locale="en">
* <p>
* If thie instance is not initalized, throw
* {@link ContainerAdapterStartupException}.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合、{@link ContainerAdapterStartupException}が発生します.
* </p>
* </#if>
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@Override
public <T> Component getBeanDesc(Class<? super T> componentClass) {
Assertion.notNull(componentClass);
assertInited();
if (getContainer().containsKey(componentClass)) {
return Component.createByClass(componentClass);
}
return null;
}
/**
* {@inheritDoc}
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@SuppressWarnings("unchecked")
@Override
public <T> T getComponent(Class<? super T> componentClass) {
Assertion.notNull(componentClass);
assertInited();
return (T) getContainer().get(componentClass);
}
/**
* {@inheritDoc}
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@SuppressWarnings("unchecked")
@Override
public <T> List<T> getComponents(Class<? super T> componentClass) {
assertInited();
Map<Class<?>, Object> components = getContainer();
if (components.containsKey(componentClass)) {
List<T> ret = new ArrayList<T>();
for (Iterator<Class<?>> itr = components.keySet().iterator(); itr
.hasNext();) {
final Class<?> c = itr.next();
final T instance = (T) components.get(c);
if (componentClass.isAssignableFrom(c)
&& ret.contains(instance) == false) {
ret.add(instance);
}
}
return ret;
}
return null;
}
/**
* {@inheritDoc}
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@Override
public <T> boolean hasComponent(Class<T> componentClass) {
assertInited();
return getContainer().containsKey(componentClass);
}
/**
* <#if locale="en">
* <p>
* Unsupported this method for {@link SimpleContainerAdapter}.
* </p>
* <#else>
* <p>
* このメソッドは{@link SimpleContainerAdapter}ではサポートされません.
* </p>
* </#if>
*
* @throws UnsupportedOperationException
* <#if locale="en">
* <p>
* throw always if this method is invoked
* </p>
* <#else>
* <p>
* このメソッドでは常に発生します
* </p>
* </#if>
*/
@Override
public <T> T injectDependency(T t) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@Override
public synchronized <T> void register(Class<? extends T> clazz) {
Assertion.notNull(clazz);
assertInited();
final T t = ClassUtil.newInstance(clazz);
register(t);
}
/**
* {@inheritDoc} <#if locale="en">
* <p>
* This method is thread-safe.
* </p>
* <#else>
* <p>
* このメソッドは同期化されています.
* </p>
* </#if>
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@SuppressWarnings("unchecked")
@Override
public synchronized <T> void register(T component) {
Assertion.notNull(component);
assertInited();
Class<T> clazz = (Class<T>) component.getClass();
final List<Class<?>> dependencyClassList = analyzeClassDependency(clazz);
for (Class<?> c : dependencyClassList) {
getContainer().put(c, component);
}
}
/**
* {@inheritDoc}
*/
@Override
public Map<Class<?>, Object> getContainer() {
return this.container;
}
/**
* <#if locale="en">
* <p>
* This method is not supported, and returns empty list.
* </p>
* <#else>
* <p>
* このメソッドはサポートされていません.常に空のリストを返します.
* </p>
* </#if>
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@Override
public List<ExceptionHandler<Throwable, Exception>> createExceptionHandlers() {
assertInited();
List<ExceptionHandler<Throwable, Exception>> handlers = getComponents(ExceptionHandler.class);
if (handlers != null && handlers.isEmpty() == false) {
return handlers;
} else {
return Collections.emptyList();
}
}
/**
* {@inheritDoc}
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*/
@Override
public GlobalExceptionHandler createGlobalExceptionHandler() {
assertInited();
return new GlobalExceptionHandler();
}
/**
*
* <#if locale="en">
* <p>
* Check if this instance is initialized correctly.
* </p>
* <#else>
* <p>
* このメソッドが初期化されているかどうかを検査します.
* </p>
* </#if>
*
* @throws ContainerAdapterStartupException
* <#if locale="en">
* <p>
* In case of thie instance is not initalized.
* </p>
* <#else>
* <p>
* このインスタンスが初期化されていない場合
* </p>
* </#if>
*
*/
protected void assertInited() {
if (getContainer() == null) {
throw new ContainerAdapterStartupException(this.getClass());
}
}
protected List<Class<?>> analyzeClassDependency(Class<?> targetClass) {
List<Class<?>> dependencyList = new ArrayList<Class<?>>();
for (Class<?> c = targetClass; c != null && c != Object.class; c = c
.getSuperclass()) {
analyzeByInterface(dependencyList, c);
}
return dependencyList;
}
protected void analyzeByInterface(List<Class<?>> dependencyList,
final Class<?> c) {
if (unacceptableClasses.contains(c)) {
return;
}
dependencyList.add(c);
final Class<?>[] interfaces = c.getInterfaces();
for (Class<?> cl : interfaces) {
analyzeByInterface(dependencyList, cl);
}
}
/**
* {@inheritDoc}
*/
@Override
public void destroy() {
container.clear();
}
}