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        // デフォルトシステムIDの日本語(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         * 引数の言語コードに応じたリソースを1度だけ作成します。
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         * 引数の言語コードに応じたリソースを1度だけ作成します。
094         * 作成したリソースオブジェクトは,内部にプールしておき,同じリソース要求が
095         * あったときは,プールのリソースを返します。
096         *
097         * @og.rev 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応する。
098         *
099         * @param       systemId        システムID(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}