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