/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.toolkit.util.resourcebundle;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 抽象的<code>ResourceBundleFactory</code>, 实现了通用的创建<code>ResourceBundle</code>
* 实例的方法.
* <p>
* 这个实现通过<code>ResourceBundleLoader</code>装入bundle的数据文件, 然后执行<code>parse</code>
* 方法取得<code>ResourceBundle</code>实例.
* </p>
* <p>
* 扩展类可以通过提供适当的<code>ResourceBundleLoader</code>来改变bundle的装入方式, 例如从文件系统或数据库中装入.
* 通过覆盖<code>parse</code>方法, 可以改变读取文件的格式, 例如
* <code>XMLResourceBundleFactory</code>以XML的格式来解释文件.
* </p>
*
* @author Michael Zhou
* @version $Id
*/
public abstract class AbstractResourceBundleFactory extends ResourceBundleFactory {
private final ResourceBundleLoader loader;
/** 创建factory, 使用当前线程的context class loader作为bundle装入器. */
public AbstractResourceBundleFactory() {
this(new ClassLoaderResourceBundleLoader());
}
/**
* 创建factory, 使用指定的class loader作为bundle装入器.
*
* @param classLoader 装入bundle的class loader
*/
public AbstractResourceBundleFactory(ClassLoader classLoader) {
this(new ClassLoaderResourceBundleLoader(classLoader));
}
/**
* 创建factory, 使用指定的loader作为bundle装器
*
* @param loader bundle装入器
*/
public AbstractResourceBundleFactory(ResourceBundleLoader loader) {
this.loader = loader;
}
/**
* 取得<code>ResourceBundleLoader</code>.
*
* @return loader
*/
public ResourceBundleLoader getLoader() {
return loader;
}
/**
* 创建<code>ResourceBundle</code>的实例.
*
* @param bundleName 要创建的bundle名称
* @return 新创建的<code>ResourceBundle</code>实例, 如果指定bundle不存在, 则返回
* <code>null</code>
* @throws ResourceBundleCreateException 指定bundle文件存在, 但创建bundle实例失败,
* 例如文件格式错误
*/
@Override
public ResourceBundle createBundle(String bundleName) throws ResourceBundleCreateException {
InputStream stream = null;
String filename = getFilename(bundleName);
if (loader != null) {
stream = loader.openStream(filename);
}
// 如果文件不存在, 则返回null.
if (stream == null) {
return null;
}
try {
// @TODO: 此处最好以URL作为system ID
return parse(new BufferedInputStream(stream), filename);
} finally {
try {
stream.close();
} catch (IOException e) {
}
}
}
/**
* 根据bundle的名称取得resource的文件名称.
*
* @param bundleName bundle的名称
* @return resource的名称
*/
protected String getFilename(String bundleName) {
return bundleName.replace('.', '/');
}
/**
* 解析输入流, 从中创建<code>ResourceBundle</code>.
*
* @param stream 输入流
* @param systemId 标准输入流的字符串(一般是文件名)
* @return resource bundle
* @throws ResourceBundleCreateException 如果解析失败
*/
protected abstract ResourceBundle parse(InputStream stream, String systemId) throws ResourceBundleCreateException;
/**
* 比较两个factory是否等效. 对于等效的factory, 给予相同的bundle名, 调用<code>createBundle</code>
* 方法, 可以得到等效的bundle实例.
*
* @param other 要比较的factory
* @return 如果等效, 则返回<code>true</code>
*/
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
try {
AbstractResourceBundleFactory otherFactory = (AbstractResourceBundleFactory) other;
return loader == null ? otherFactory.loader == null : loader.equals(otherFactory.loader);
} catch (NullPointerException npe) {
return false;
} catch (ClassCastException cce) {
return false;
}
}
/**
* 取得factory的hash值, 如果两个factory等效, 则它们的hash值也相等.
*
* @return factory的hash值
*/
@Override
public int hashCode() {
return loader == null ? 0 : loader.hashCode();
}
}