    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.hayabusa.resource;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.SystemManager;
    020import org.opengion.fukurou.util.Cleanable;
    021
    022import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
    023import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.3 (2016/03/04)
    024
    025/**
    026 * java.util.ResourceBundle クラスを複数管理するResourceManager をリソース毎に作成します。
    027 * ResourceFactory#newInstance( String lang ) により，ResourceManager の要求毎に
    028 * 新しくオブジェクトを作成するのではなく,ロケール毎に ResourceManager を作成します。
    029 * ResourceManagerは,ロケール毎に 内部のプールに保存されています。
    030 *
    031 * リソース作成時に指定するロケールは,ISO 言語コード(ISO-639 で定義される 2 桁の小文字)
    032 * <a href ="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
    033 * http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt</a>を使用して下さい。
    034 * ただし，内部的に Locale を構築していますが,その正しさは,チェックされていませんので,
    035 * 指定するロケールに応じた properties ファイルを用意しておいて下さい。
    036 *
    037 * @og.group リソース管理
    038 *
    039 * @version  4.0
    040 * @author   Kazuhiko Hasegawa
    041 * @since    JDK5.0,
    042 */
    043public final class ResourceFactory {
    044        private static final String SYSTEM_ID = HybsSystem.sys( "SYSTEM_ID" );
    045
    046        // デフォルトシステムＩＤの日本語(ja)は、特別扱いする。
    047        private static final ResourceManager JA_MANAGER = new ResourceManager( SYSTEM_ID,"ja",true );                           // 6.4.1.1 (2016/01/16) ja_Manager → JA_MANAGER  refactoring
    048
    049        /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。  */
    050        private static final ConcurrentMap<String,ResourceManager> POOL = new ConcurrentHashMap<>();                            // 6.4.3.3 (2016/03/04)
    051
    052        // 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
    053        static {
    054                final Cleanable clr = new Cleanable() {
    055                        /**
    056                         * 初期化(クリア)します。
    057                         * 主に、キャッシュクリアで利用します。
    058                         */
    059                        public void clear() {
    060                                ResourceFactory.clear();
    061                        }
    062                };
    063
    064                SystemManager.addCleanable( clr );
    065        }
    066
    067        /**
    068         *  デフォルトコンストラクターをprivateにして、
    069         *  オブジェクトの生成をさせないようにする。
    070         *
    071         */
    072        private ResourceFactory() {
    073        }
    074
    075        /**
    076         * ResourceManager オブジェクトを取得します。
    077         * 引数の言語コードに応じたリソースを１度だけ作成します。
    078         * 作成したリソースオブジェクトは，内部にプールしておき，同じリソース要求が
    079         * あったときは，プールのリソースを返します。
    080         *
    081         * @param       lang    言語コード(null の場合は、"ja" とします。)
    082         *
    083         * @return      ResourceManagerオブジェクト
    084         * @og.rtnNotNull
    085         */
    086        public static ResourceManager newInstance( final String lang ) {
    087                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    088                return lang == null || "ja".equalsIgnoreCase( lang ) ? JA_MANAGER : newInstance( SYSTEM_ID,lang,true ) ;
    089        }
    090
    091        /**
    092         * ResourceManager オブジェクトを取得します。
    093         * 引数の言語コードに応じたリソースを１度だけ作成します。
    094         * 作成したリソースオブジェクトは，内部にプールしておき，同じリソース要求が
    095         * あったときは，プールのリソースを返します。
    096         *
    097         * @og.rev 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応する。
    098         *
    099         * @param       systemId        システムＩＤ(null の場合は、HybsSystem の SYSTEM_ID パラメータ)
    100         * @param       lang            言語コード(null の場合は、"ja" とします。)
    101         * @param       initLoad        リソースデータの先読み可否(true:先読みする)
    102         *
    103         * @return      ResourceManagerオブジェクト
    104         */
    105        public static ResourceManager newInstance( final String systemId,final String lang,final boolean initLoad ) {
    106                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    107                final String sys = (systemId == null ) ? SYSTEM_ID : systemId ;
    108                final String lg  = (lang     == null ) ? "ja"      : lang;
    109
    110                if( SYSTEM_ID.equalsIgnoreCase( sys ) && "ja".equalsIgnoreCase( lg ) ) {
    111                        return JA_MANAGER ;
    112                }
    113
    114                final String key = sys + lg ;
    115
    116                // Map#computeIfAbsent ： 戻り値は、新しい値。追加有り、置換有り、削除有り
    117                return POOL.computeIfAbsent( key , k -> new ResourceManager( sys,lg,initLoad ) );
    118        }
    119
    120        /**
    121         * キャッシュ(プール)から、すべてのオブジェクトをクリアします。
    122         * この時、POOLされているオブジェクトは、ResourceManager#clear() メソッドを
    123         * 呼び出します。
    124         *
    125         * @og.rev 3.5.5.7 (2004/05/10) CodeSelectionFactoryをクリアします。
    126         * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
    127         */
    128        public static void clear() {
    129                JA_MANAGER.clear();
    130
    131        //      POOL.forEach( (k,v) -> v.clear() );                     // ConcurrentMap なのでnullチェック不要
    132                POOL.values().forEach( v -> v.clear() );        // ConcurrentMap なのでnullチェック不要
    133                POOL.clear();
    134        }
    135
    136        /**
    137         * キャッシュ(プール)から、すべてのGUI情報オブジェクトをクリアします。
    138         *
    139         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
    140         * @og.rev 6.4.3.3 (2016/03/04) Map#forEach で対応する。
    141         */
    142        public static void guiClear() {
    143                JA_MANAGER.guiClear();
    144
    145        //      POOL.forEach( (k,v) -> v.guiClear() );                  // ConcurrentMap なのでnullチェック不要
    146                POOL.values().forEach( v -> v.guiClear() );             // ConcurrentMap なのでnullチェック不要
    147        }
    148}