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 java.util.Map; 019import java.util.WeakHashMap; 020 021import org.opengion.hayabusa.common.HybsSystem; 022import org.opengion.hayabusa.common.SystemManager; 023import org.opengion.fukurou.db.DBUtil; 024import org.opengion.fukurou.util.Cleanable; 025import org.opengion.fukurou.db.ApplicationInfo; 026 027/** 028 * 事業所(CDJGS) , 年月(YYYYMM) に対応した休日カレンダデータを作成するファクトリクラスです。 029 * 030 * カレンダデータは、1日(DY1)~31日(DY31)までの日付け欄に対して、0:平日 1:休日 という 031 * データを持っています。実際には、内部では true:平日 false:休日 という持ち方をします。 032 * (カレンダDBは、文字列ですが、内部で持つ場合は、数字で管理しています。) 033 * 034 * 通常のカレンダでは、月毎に、(2月は、年によって)最大日付けが変わります。 035 * これは、カレンダデータクラスとしては、-1 を設定しておきます。 036 * 037 * カレンダデータには、3つのレベルのオブジェクト作成方法が適用されます。 038 * 他のリソースの3つのレベルとは異なり、エンジンリソースからの読み取りは 039 * 存在しなく、第4の方法が加わった事により、3つの方法になっています。 040 * 041 * まず、読込フラグ(FGLOAD)='1'のカレンダデータは、このCalendarFactoryオブジェクトが 042 * 構築された時に、すべてキャッシュとして内部メモリに読み取ります。 043 * 読込フラグが、'1' 以外のデータは、初期起動時には、メモリにキャッシュされず 044 * 実際に使用されるまで、オブジェクトが作成されません。 045 * カレンダの場合、過去の使用される可能性が低いデータまで、キャッシュしない様に、 046 * このフラグを使用して、メモリの節約を図ることが可能になります。 047 * 048 * 読込フラグ(FGLOAD)自動設定機能を使用すれば、読み取ったラベルデータに対して、 049 * 読込フラグ(FGLOAD)に '1' を自動的にセットします。この機能により、一度でも 050 * 読み取ったことがあるデータに '1' を付け、次回起動時には、メモリキャッシュさせる 051 * 事と、一度も読み取っていないデータを判別して、データ削除等のメンテナンスに 052 * 使用することが可能です。 053 * カレンダに限定すれば、当面使用されない先のカレンダ(1年分など)を登録する時に、 054 * 読込フラグ(FGLOAD)='0' にしておけば、実際に読み取られるまで、メモリキャッシュ 055 * されないため、さらにメモリ効率が向上します。 056 * 057 * 2つめの方法は、キャッシュに存在しない場合は、DBから読み取ります。 058 * 059 * 3つめは、カレンダ特有の方法で、DBにデータが存在しない場合の設定です。 060 * これは、カレンダテーブル未設定時でも、カレンダとして使用できるように 061 * 自動的にカレンダデータを作成します。日曜日を休日として自動設定します。 062 * 063 * @og.rev 3.6.0.0 (2004/09/17) 新規作成 064 * @og.group リソース管理 065 * 066 * @version 4.0 067 * @author Kazuhiko Hasegawa 068 * @since JDK5.0, 069 */ 070public final class CalendarFactory { 071 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理するのではなく、LOCKオブジェクトで、同期処理を行います。 */ 072 private static final Map<String,CalendarData> DATA_POOL = new WeakHashMap<>(); // 6.4.1.1 (2016/01/16) pool → DATA_POOL refactoring 073 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理するのではなく、LOCKオブジェクトで、同期処理を行います。 */ 074 private static final Map<String,CalendarQuery> QUERY_POOL = new WeakHashMap<>(); // 6.4.1.1 (2016/01/16) queryClassPool → QUERY_POOL refactoring 075 // 4.0.0.0 PGカレンダーの初期設定をシステムリソースに変更 076 private static CalendarData pgCalData ; 077 private static final String PG_CALENDAR_DATA_CLASS = HybsSystem.sys( "DEFAULT_CALENDAR_CLASS"); 078 private static final Object LOCK = new Object(); // 6.4.1.1 (2016/01/16) lock → LOCK refactoring 079 080 /** カレンダDBの接続先を、取得します。 */ 081 private static final String DBID = HybsSystem.sys( "RESOURCE_CALENDAR_DBID" ); 082 083 /** カレンダDBを使用するかどうかを指定します。(互換モード) */ 084 private static boolean useDB = HybsSystem.sysBool( "USE_CALENDAR_DATABASE" ); 085 086 /** 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 */ 087 private static final ApplicationInfo APP_INFO; // 6.4.1.1 (2016/01/16) appInfo → APP_INFO refactoring 088 089 /** 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理 */ 090 static { 091 final Cleanable clr = new Cleanable() { 092 /** 093 * 初期化(クリア)します。 094 * 主に、キャッシュクリアで利用します。 095 */ 096 public void clear() { 097 CalendarFactory.clear(); 098 } 099 }; 100 101 SystemManager.addCleanable( clr ); 102 103 /** コネクションにアプリケーション情報を追記するかどうか指定 */ 104 final boolean USE_DB_APPLICATION_INFO = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ; 105 106 // 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 107 if( USE_DB_APPLICATION_INFO ) { 108 final String SYSTEM_ID = HybsSystem.sys( "SYSTEM_ID" ); 109 APP_INFO = new ApplicationInfo(); 110 // ユーザーID,IPアドレス,ホスト名 111 APP_INFO.setClientInfo( SYSTEM_ID,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME ); 112 // 画面ID,操作,プログラムID 113 APP_INFO.setModuleInfo( "CalendarFactory",null,null ); 114 } 115 else { 116 APP_INFO = null; 117 } 118 } 119 120 /** 121 * デフォルトコンストラクターをprivateにして、 122 * オブジェクトの生成をさせないようにする。 123 */ 124 private CalendarFactory() { } 125 126 /** 127 * CalendarData オブジェクトを取得します。 128 * 作成したCalendarDataオブジェクトは、内部にプールしておき、同じリソース要求が 129 * あったときは、プールの CalendarDataを返します。 130 * DBにデータが存在しない場合は、自動でカレンダを作成します。 131 * 132 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 133 * @og.rev 4.0.0.0 (2007/08/29) カレンダーテーブルが存在しない場合のデフォルトのカレンダーデータをシステムリソースで設定する 134 * @og.rev 6.0.4.0 (2014/11/28) NullPointerException が発生するので、事前にチェックします。 135 * @og.rev 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応するのと、HybsSystem#newInstance(String,String)を利用します。 136 * @og.rev 6.9.9.3 (2018/09/25) 可変引数に変更します(PMD Rather than using a lot of String arguments, consider using a container object for those values.)。 137 * 138 * @param cls CalendarQueryオブジェクトを名称を指定します。 139 * @param inArgs データベース検索時の可変引数 140// * @param arg1 データベース検索時の第1引数 141// * @param arg2 データベース検索時の第2引数 142// * @param arg3 データベース検索時の第3引数 143// * @param arg4 データベース検索時の第4引数 144 * 145 * @return CalendarDataオブジェクト 146 */ 147// public static CalendarData getCalendarData( final String cls,final String arg1,final String arg2,final String arg3,final String arg4 ) { 148 public static CalendarData getCalendarData( final String cls,final String... inArgs ) { 149 150 // 4.0.0.0 PGカレンダーの初期設定をシステムリソースに変更 151 synchronized( LOCK ) { 152 if( pgCalData == null ) { 153 pgCalData = HybsSystem.newInstance(PG_CALENDAR_DATA_CLASS); 154 } 155 } 156 157 if( ! useDB || cls == null ) { return pgCalData; } 158 159 CalendarData calData ; 160 161// final String key = cls + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 ; 162 final String key = cls + ":" + String.join( ":" , inArgs ); // 6.9.9.3 (2018/09/25) 163 synchronized( LOCK ) { 164 calData = DATA_POOL.get( key ) ; 165 } 166 167 if( calData == null ) { 168 // 6.4.3.3 (2016/03/04) Map#computeIfAbsent で対応するのと、HybsSystem#newInstance(String,String)を利用します。 169 // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし 170 final CalendarQuery query = 171 QUERY_POOL.computeIfAbsent( cls , k -> HybsSystem.newInstance( "CalendarQuery_" , k ) ); 172 173// final String[] args = query.checkArgment( arg1,arg2,arg3,arg4 ); 174 final String[] args = query.checkArgment( inArgs ); // 6.9.9.3 (2018/09/25) 175 final String[][] vals = DBUtil.dbExecute( query.getQuery(),args,APP_INFO,DBID ); // 3.8.7.0 (2006/12/15) 176 final boolean isFlat = query.isFlatTable(); 177 178 if( vals != null && vals.length > 0 ) { 179 calData = new CalendarDBData( vals,isFlat ); 180 // 完全同期ではない。DB処理中に別にもDB処理を行い、 181 // 先に put されたとしても、同一キーに同じ属性のオブジェクトを 182 // 登録するだけなので、実質的な問題は発生しない。 183 // これが、List などの順序が関係すると、このコードは使えない。 184 synchronized( LOCK ) { 185 DATA_POOL.put( key,calData ); 186 } 187 } 188 else { 189 // カレンダテーブルにデータが存在しない場合。 190 // 4.0.0.0 PGカレンダーの初期設定をシステムリソースに変更 191 calData = pgCalData; 192 } 193 } 194 return calData ; 195 } 196 197 /** 198 * キャッシュ(プール)から、すべてのオブジェクトをクリアします。 199 * 200 */ 201 public static void clear() { 202 synchronized( LOCK ) { 203 DATA_POOL.clear(); 204 QUERY_POOL.clear(); 205 useDB = HybsSystem.sysBool( "USE_CALENDAR_DATABASE" ); 206 } 207 } 208}