/*
* 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.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.seasar.framework.container.ExternalContext;
import org.seasar.framework.container.ExternalContextComponentDefRegister;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.util.SmartDeployUtil;
import org.seasar.framework.env.Env;
import org.seasar.framework.exception.EmptyRuntimeException;
import org.seasar.framework.exception.JarDuplicatedException;
import org.seasar.framework.log.Logger;
import org.seasar.framework.util.DisposableUtil;
import org.seasar.framework.util.InputStreamUtil;
/**
* 唯一の{@link org.seasar.framework.container.S2Container S2コンテナ}
* を提供するためのファクトリクラスです。
* <p>
* シングルトンS2コンテナファクトリは、設定ファイルに基づいてS2コンテナを生成・初期化し、それを保持します。
* 保持されるS2コンテナは、このクラスをロードしたクラスローダで一意になります。
* </p>
* <p>
* デフォルトの設定ファイル名は<code>app.dicon</code>となります。
* </p>
* <p>
* シングルトンS2コンテナファクトリの標準的な利用方法としては、 アプリケーション開始時に{@link #init()}を呼び出して、
* {@link #getContainer()}でS2コンテナを取得し、 アプリケーション終了時に{@link #destroy()}を呼び出します。
* Webアプリケーションであれば
* {@link javax.servlet.Servlet#init(javax.servlet.ServletConfig)}で
* {@link #init()}を、 {@link javax.servlet.Servlet#destroy()}で{@link #destroy()}
* を呼び出します。
* </p>
*
* @author koichik
* @author goto
*/
public class SingletonS2ContainerFactory {
private static final Logger logger = Logger
.getLogger(SingletonS2ContainerFactory.class);
private static String configPath = "app.dicon";
private static ExternalContext externalContext;
private static ExternalContextComponentDefRegister externalContextComponentDefRegister;
private static S2Container container;
private SingletonS2ContainerFactory() {
}
/**
* 設定ファイルのファイルパスを返します。
*
* @return 設定ファイルのファイルパス
*/
public static String getConfigPath() {
return configPath;
}
/**
* 設定ファイルのファイルパスを設定します。
*
* @param path
* 設定ファイルのファイルパス
*/
public static void setConfigPath(String path) {
configPath = path;
}
/**
* {@link org.seasar.framework.container.ExternalContext 外部コンテキスト}を返します。
*
* @return 外部コンテキスト
*/
public static ExternalContext getExternalContext() {
return externalContext;
}
/**
* {@link org.seasar.framework.container.ExternalContext 外部コンテキスト}を設定します。
*
* @param extCtx
* 外部コンテキスト
*/
public static void setExternalContext(ExternalContext extCtx) {
externalContext = extCtx;
}
/**
* {@link org.seasar.framework.container.ExternalContextComponentDefRegister
* 外部コンテキストコンポーネント定義レジスタ}を返します。
*
* @return 外部コンテキストコンポーネント定義レジスタ
*/
public static ExternalContextComponentDefRegister getExternalContextComponentDefRegister() {
return externalContextComponentDefRegister;
}
/**
* {@link org.seasar.framework.container.ExternalContextComponentDefRegister
* 外部コンテキストコンポーネント定義レジスタ}を設定します。
*
* @param extCtxComponentDefRegister
* 外部コンテキストコンポーネント定義レジスタ
*/
public static void setExternalContextComponentDefRegister(
ExternalContextComponentDefRegister extCtxComponentDefRegister) {
externalContextComponentDefRegister = extCtxComponentDefRegister;
}
/**
* 設定ファイルに基づいてS2コンテナを生成・初期化し、それを保持します。 既にS2コンテナが保持されている場合は何もしません。
* <p>
* S2コンテナを生成した後、 初期化を行なう前に必要に応じて、
* 外部コンテキストおよび外部コンテキストコンポーネント定義レジスタをS2コンテナに設定します。
* </p>
*
* @see S2ContainerFactory#create(String)
* @see org.seasar.framework.container.ExternalContext
* @see org.seasar.framework.container.ExternalContextComponentDefRegister
*/
public static void init() {
if (container != null) {
return;
}
checkVersions();
container = S2ContainerFactory.create(configPath);
if (container.getExternalContext() == null) {
if (externalContext != null) {
container.setExternalContext(externalContext);
}
} else if (container.getExternalContext().getApplication() == null
&& externalContext != null) {
container.getExternalContext().setApplication(
externalContext.getApplication());
}
if (container.getExternalContextComponentDefRegister() == null
&& externalContextComponentDefRegister != null) {
container
.setExternalContextComponentDefRegister(externalContextComponentDefRegister);
}
container.init();
logger.info("Running on [ENV]" + Env.getValue() + ", [DEPLOY MODE]"
+ SmartDeployUtil.getDeployMode(container));
}
/**
* S2コンテナやその他の終了処理を行ないます。
*/
public static void destroy() {
if (container == null) {
return;
}
container.destroy();
container = null;
DisposableUtil.dispose();
}
/**
* 唯一のS2コンテナを返します。 S2コンテナが保持されていない場合、
* {@link org.seasar.framework.exception.EmptyRuntimeException}をスローします。
*
* @return S2コンテナ
*/
public static S2Container getContainer() {
if (container == null) {
throw new EmptyRuntimeException("S2Container");
}
return container;
}
/**
* 保持するS2コンテナを設定します。
*
* @param c
* S2コンテナ
*/
public static void setContainer(S2Container c) {
container = c;
}
/**
* S2コンテナを保持しているかどうかを返します。
*
* @return S2コンテナを保持している場合は<code>true</code>、そうでない場合は<code>false</code>
*/
public static boolean hasContainer() {
return container != null;
}
private static void checkVersions() {
checkVersion("s2-framework");
checkVersion("s2-extension");
checkVersion("s2-tiger");
}
private static void checkVersion(final String artifactId) {
final Map versions = getVersions(artifactId);
if (versions.isEmpty()) {
return;
}
if (versions.size() > 1) {
throw new JarDuplicatedException(artifactId, versions);
}
final String version = (String) versions.keySet().iterator().next();
final List urlList = (List) versions.values().iterator().next();
if (urlList.size() > 1) {
logger.log("WSSR0016",
new Object[] { artifactId, version, urlList });
return;
}
logger.log("ISSR0009", new Object[] { artifactId, version });
}
private static Map getVersions(final String artifactId) {
final Map versions = new HashMap();
try {
final String name = "META-INF/maven/org.seasar.container/"
+ artifactId + "/pom.properties";
final Enumeration urls = Thread.currentThread()
.getContextClassLoader().getResources(name);
while (urls.hasMoreElements()) {
URL url = (URL) urls.nextElement();
final InputStream is = url.openStream();
try {
final Properties props = new Properties();
props.load(is);
String version = props.getProperty("version");
final List urlList;
if (versions.containsKey(version)) {
urlList = (List) versions.get(version);
} else {
urlList = new ArrayList();
versions.put(version, urlList);
}
urlList.add(url.toExternalForm());
} finally {
InputStreamUtil.close(is);
}
}
} catch (final Exception ignore) {
}
return versions;
}
}