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.fukurou.util;
017
018// import java.text.DateFormat;
019// import java.text.SimpleDateFormat;
020// import java.util.Locale;
021// import java.util.Calendar;
022import java.util.ArrayList;
023import java.util.Map;
024import java.util.HashMap;
025
026/**
027 * SystemParameter は、{@XXXX} 文字列を処理するクラスです。
028 * このクラスでは、{@XXXX} 文字列を別の文字列と置き換えることや、
029 * 予め予約されている予約語 {@DATE.XXXX} 文字列を置き換えます。
030 * 通常の {@XXXX} 文字列の置き換えは、キーと値のペアを、HybsEntry オブジェクトに
031 * セットして、その配列を受け取って処理します。
032 *
033 * 以下の値はあらかじめ、動的に作成されます。
034 * ・DATE.YMD       8byte の今日のシステム日付(yyyyMMdd)
035 * ・DATE.YMDH    14byte の今日のシステム日時(yyyyMMddHHmmss)
036 * ・DATE.HMS       6byte の今日のシステム時間(HHmmss)
037 *
038 * @og.group ユーティリティ
039 *
040 * @version  4.0
041 * @author   Kazuhiko Hasegawa
042 * @since    JDK5.0,
043 */
044public final class SystemParameter {
045
046//      private final Map<String,String> sysMap = new HashMap<String,String>();
047        /** 改行コード */
048        public static final String CR = System.getProperty("line.separator");   // 5.1.9.0 (2010/08/01) 追加
049
050        //      5.5.7.2 (2012/10/09) HybsDateUtil を利用するため、削除します。
051//      private static final Map<String,String>   DATE_FORMAT = new HashMap<String,String>();       // 5.3.4.0 (2011/04/01)
052//      static {
053//              DATE_FORMAT.put( "SYS.YMD"              ,"yyyyMMdd"                             );
054//              DATE_FORMAT.put( "SYS.YMDH"     ,"yyyyMMddHHmmss"               );
055//              DATE_FORMAT.put( "SYS.HMS"              ,"HHmmss"                               );
056//              DATE_FORMAT.put( "DATE.YMD"     ,"yyyyMMdd"                     );
057//              DATE_FORMAT.put( "DATE.Y2MD"    ,"yyMMdd"                               );
058//              DATE_FORMAT.put( "DATE.YM"              ,"yyyyMM"                               );
059//              DATE_FORMAT.put( "DATE.HMS"     ,"HHmmss"                               );
060//              DATE_FORMAT.put( "DATE.YMDHMS"  ,"yyyyMMddHHmmss"               );
061//              DATE_FORMAT.put( "DATE.YMDF"    ,"yyyy/MM/dd"                   );
062//              DATE_FORMAT.put( "DATE.Y2MDF"   ,"yy/MM/dd"                     );
063//              DATE_FORMAT.put( "DATE.YMF"     ,"yyyy/MM"                              );
064//              DATE_FORMAT.put( "DATE.HMSF"    ,"HH:mm:ss"                     );
065//              DATE_FORMAT.put( "DATE.YMDHMSF" ,"yyyy/MM/dd/ HH:mm:ss" );
066//              DATE_FORMAT.put( "DATE.EEE"     ,"EEE"                                  );
067//      }
068
069        private final String    original ;
070        // 5.5.7.2 (2012/10/09) Calendarオブジェクトから、String時刻に変更。
071//      private final Calendar  rightNow;                                                                               // 5.3.4.0 (2011/04/01)
072//      private final String    RIGHT_NOW = HybsDateUtil.getDate( "yyyyMMdd" ); // 5.7.4.1 (2014/03/14) 廃止
073
074        private final String[] clms;
075        private final String[] formats;
076
077        /**
078         *  {&#064;XXXX} の特殊文字を含む文字列を、置き換えます。
079         * 対象外の文字列は、そのまま、残されます。
080         *
081         * @og.rev 5.1.8.0 (2010/07/01) パース方法見直し(StringTokenizerでは、{&#064;XXXX}が連続してある場合に対応できない)
082         * @og.rev 5.3.2.0 (2011/02/01) original データを、パース結果を利用するように修正する。
083         * @og.rev 5.3.4.0 (2011/04/01) {&#064;DATE.XXXX} を処理できるように機能追加
084         * @og.rev 5.3.5.0 (2011/05/01) {&#064;SYS.XXXX} は、廃止
085         * @og.rev 5.5.7.2 (2012/10/09) rightNow をCalendarオブジェクト ではなく、String時刻とします。
086         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
087         *
088         * @param       orig    変換する文字列(オリジナル)
089         */
090        public SystemParameter( final String orig ) {
091//              rightNow = Calendar.getInstance();
092
093                if( orig == null || orig.length() == 0 || orig.indexOf( "{@" ) < 0 ) {
094                        clms     = null;
095                        formats  = null;
096                        original = orig;                // 5.3.2.0 (2011/02/01)
097                }
098                else {
099                        StringBuilder buf = new StringBuilder(orig.length());           // 5.3.2.0 (2011/02/01)
100
101                        ArrayList<String> fmtList = new ArrayList<String>();
102                        ArrayList<String> clmList = new ArrayList<String>();
103
104                        // 5.1.8.0 (2010/07/01) パース方法見直し
105                        int start = 0;
106                        int index = orig.indexOf( "{@" );
107                        String val ;
108                        while( index >= 0 ) {
109//                              buf.append(  orig.substring( start, index ) );          // 5.3.2.0 (2011/02/01)
110//                              fmtList.add( orig.substring( start, index ) );
111                                val = orig.substring( start, index );                                   // 5.3.4.0 (2011/04/01)
112                                buf.append(  val );
113                                fmtList.add( val );
114                                int end = orig.indexOf( '}',index );
115                                if( end < 0 ) {
116                                        String errMsg = "{@ と } との対応関係がずれています。" + CR
117                                                                + "str=[" + orig + "] : index=" + index ;
118                                        throw new RuntimeException( errMsg );
119                                }
120                                String param = orig.substring( index+2,end );
121//                              if( param.startsWith( "SYS." ) || param.startsWith( "DATE." ) ) {
122                                if( param.startsWith( "DATE." ) ) {             // 5.3.5.0 (2011/05/01) {&#064;SYS.XXXX} は、廃止
123//                                      val = getDateFormat( param );
124                                        val = getDateFormat( param.substring( 5 ) );    // 5.5.7.2 (2012/10/09) HybsDateUtil を利用時に "DATE." は不要
125                                        clmList.add( null );            // パースした場合は、clmList は、使用しない。
126                                        buf.append( val );
127                                }
128                                else {
129                                        clmList.add( param );
130                                        buf.append( "{@" ).append( param ).append( "}" );               // 元のままの文字列を生成
131                                }
132                                start = end+1;
133                                index = orig.indexOf( "{@",start );
134                        }
135//                      buf.append(  orig.substring( start, orig.length() ) );          // 5.3.2.0 (2011/02/01)
136//                      fmtList.add( orig.substring( start, orig.length() ) );
137                        val = orig.substring( start, orig.length() );                           // 5.3.4.0 (2011/04/01)
138                        buf.append(  val );
139                        fmtList.add( val );
140
141                        original = buf.toString();              // 5.3.2.0 (2011/02/01)
142                        if( original.indexOf( "{@" ) < 0 ) {
143                                clms     = null;
144                                formats  = null;
145                        }
146                        else {
147                                clms    = clmList.toArray( new String[clmList.size()] );
148                                formats = fmtList.toArray( new String[fmtList.size()] );
149                        }
150                }
151        }
152
153        /**
154         * 日付関係の情報を簡易的に取り出す処理を行います。
155         *
156         * 引数は、"XXXX AA BB CC" という状態で受け取ります。
157         *
158         * 処理の詳細は、{@link org.opengion.fukurou.util.HybsDateUtil#getDateFormat( String,String,String,int ) }
159         * または、{@link org.opengion.hayabusa.taglib.CommonTagSupport#getDateFormat( String ) } を
160         * 参照してください。
161         *
162         * @og.rev 5.3.4.0 (2011/04/01) 新規追加
163         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
164         * @og.rev 5.5.8.2 (2012/11/09) prmA の判定に、null と ゼロ文字列を判定する。
165         * @og.rev 5.7.4.1 (2014/03/14) AA 引数の@解析後のコマンド判定方法を、8ケタ以下から先頭が数字以外に変更します。
166         * @og.rev 5.7.4.1 (2014/03/14) taglib.CommonTagSupport#getDateFormat( String ) と処理を合わせます。
167         * @og.rev 5.7.4.2 (2014/03/20) リクエストパラメータ(@で始まる引数)は使えません。
168         *
169         * @param   value パラメータ(引数は、"DATE.XXXX AA BB" などという状態)
170         *
171         * @return   メッセージ情報
172         * @see         org.opengion.fukurou.util.HybsDateUtil#getDateFormat( String,String,String,int )
173         * @see         org.opengion.hayabusa.taglib.CommonTagSupport#getDateFormat( String )
174         */
175        private String getDateFormat( final String value ) {
176                // 5.7.4.1 (2014/03/14) taglib.CommonTagSupport#getDateFormat( String ) と処理を合わせます。
177                String[] vals = StringUtil.csv2Array( value,' ' );
178
179                String key = vals[0] ;
180
181                String prmA = (vals.length >= 2) ? vals[1] : null ;
182                String prmB = (vals.length >= 3) ? vals[2] : null ;
183                String prmC = (vals.length >= 4) ? vals[vals.length-1] : null ;              // 互換性。最後の値が、CC引数
184
185                // 5.7.4.2 (2014/03/20) 現時点では、SystemParameter 処理にはリクエスト変数は使えないので、@変数も使えない。
186                if( prmA != null && prmA.startsWith( "@" ) ) {
187//                      prmA = getDateFormat( prmA.substring(1) );              // getRequestValue ではなく、自身を再呼出し
188                        String errMsg = "AA引数に、リクエストパラメータ(@で始まる引数)は使えません。value=[" + value + "]" ;
189                        throw new RuntimeException( errMsg );
190                }
191
192                if( prmB != null && prmB.startsWith( "@" ) ) {
193//                      prmB = getDateFormat( prmB.substring(1) );              // getRequestValue ではなく、自身を再呼出し
194                        String errMsg = "BB引数に、リクエストパラメータ(@で始まる引数)は使えません。value=[" + value + "]" ;
195                        throw new RuntimeException( errMsg );
196                }
197
198                if( prmC != null && prmC.startsWith( "@" ) ) {
199//                      prmC = getDateFormat( prmC.substring(1) );              // getRequestValue ではなく、自身を再呼出し
200                        String errMsg = "CC引数に、リクエストパラメータ(@で始まる引数)は使えません。value=[" + value + "]" ;
201                        throw new RuntimeException( errMsg );
202                }
203
204                // 5.7.4.1 (2014/03/14) AA 引数の@解析後のコマンド判定方法を、8ケタ以下から先頭が数字以外に変更します。
205                if( prmA != null && prmA.length() > 0 ) {
206                        char chA = prmA.charAt(0);
207                        if( chA < '0' || chA > '9' ) {            // 先頭が、数字以外の場合は、コマンドなので、一つずつずらす。
208                                prmC = prmB;
209                                prmB = prmA;
210                                prmA = null;
211                        }
212                }
213
214                // 5.7.4.1 (2014/03/14) CC 引数を、"H" , "D" , "M" 以外でも使用できるように拡張します。
215                int intC = 0;
216                if( prmC != null && prmC.length() > 0 ) {
217                        try { 
218                                intC = Integer.parseInt( prmC );
219                        }
220                        catch( NumberFormatException ex ) {
221                                String errMsg = "CC引数が数字ではありません。value=[" + value + "]" 
222                                                                + ex.getMessage() ;
223                                System.err.println( errMsg );
224                        }
225                }
226
227                // prmA が null か、isEmpty() の場合は、現在時刻が使用される。
228                return HybsDateUtil.getDateFormat( key,prmA,prmB,intC );        // 5.7.4.1 (2014/03/14) CC 引数を拡張します。
229
230// 5.7.4.1 (2014/03/14) taglib.CommonTagSupport#getDateFormat( String ) と処理を合わせます。
231//              String[] vals = StringUtil.csv2Array( value,' ' );
232//
233//              String key = vals[0].trim() ;
234//
235//              String prmA = null;                             // 5.5.7.2 (2012/10/09) 引数として渡すので上位で初期化しておく。
236//              String prmB = null;
237//              if( vals.length == 3 ) { prmB = vals[2].trim(); }
238//
239//              if( vals.length > 1 ) {
240//                      prmA = vals[1].trim();
241//                      if( prmA.startsWith( "@" ) ) {
242//                              prmA = getDateFormat( prmA.substring(1) );
243//                      }
244//
245//                      // prmA の@解析後、8ケタ以下の場合は、コマンドとみなし、prmB にセットし、自身は、null をセットする。
246//                      if( prmA != null && prmA.length() < 8 ) {
247//                              prmB = prmA;
248//                              prmA = null;
249//                      }
250//              }
251//
252//              if( prmA == null || prmA.isEmpty() ) { prmA = RIGHT_NOW; }              // 5.5.8.2 (2012/11/09) null と ゼロ文字列を判定する。
253//              return HybsDateUtil.getDateFormat( key,prmA,prmB );                             // 5.5.7.2 (2012/10/09) HybsDateUtil を利用する
254        }
255
256        /**
257         *  {&#064;XXXX} の特殊文字を含む文字列を、置き換えます。
258         * 対象外の文字列は、そのまま、残されます。
259         *
260         * @og.rev 5.3.4.0 (2011/04/01) 判定方法 修正
261         *
262         * @param       entry   置換文字列のキーと値のペアを管理しているEntryオブジェクトの配列
263         *
264         * @return      置換後の文字列
265         */
266        public String replace( final HybsEntry[] entry ) {
267//              if( orginal == null ) { return null; }
268//              int index = orginal.indexOf( "{@" );
269//              if( index < 0 ) { return orginal; }
270//              if( formats == null || clms == null ) { return original; }
271                if( formats == null ) { return original; }              // 5.3.4.0 (2011/04/01) 判定方法 修正
272                if( entry == null || entry.length == 0 ) { return original; }
273
274                // HybsEntry[] データを、Mapにマッピングします。
275                Map<String, String> sysMap = new HashMap<String, String>();
276//              if( entry != null ) {
277                        int size = entry.length;
278                        for( int i=0; i<size; i++ ) {
279                                sysMap.put( entry[i].getKey(),entry[i].getValue() );
280                        }
281//              }
282                return replace( sysMap );
283        }
284
285        /**
286         *  {&#064;XXXX} の特殊文字を含む文字列を、置き換えます。
287         * 対象外の文字列は、そのまま、残されます。
288         *
289         * @param  map  置換文字列のキーと値のペアを管理しているMapオブジェクト
290         *
291         * @return      置換後の文字列
292         */
293        public String replace( final Map<String,String> map ) {
294//              if( formats == null || clms == null ) { return original; }
295                if( formats == null ) { return original; }              // 5.3.4.0 (2011/04/01) 判定方法 修正
296//              if( map == null || map.size() == 0 ) { return original; }
297                if( map == null || map.isEmpty() ) { return original; }
298
299                StringBuilder sb = new StringBuilder();
300                for( int i=0; i<formats.length; i++ ) {
301                        sb.append( formats[i] );
302                        if( i < clms.length && clms[i] != null ) {           // 5.3.4.0 (2011/04/01) nullチェック追加
303                                sb.append(  StringUtil.nval( map.get( clms[i] ), "" ) );
304                        }
305                }
306
307                return sb.toString();
308        }
309
310        /**
311         * フォーマットをパースした結果から、カラム一覧を配列形式で返します。
312         *
313         * @og.rev 5.1.7.0 (2010/06/01) 新規作成
314         *
315         * @return カラム配列
316         */
317        public String[] getColumns() {
318                if( clms == null ) { return new String[0]; }
319                return clms.clone();
320        }
321
322        /**
323         * フォーマットをパースした結果から、フォーマット一覧を配列形式で返します。
324         *
325         * @og.rev 5.1.7.0 (2010/06/01) 新規作成
326         *
327         * @return フォーマット配列
328         */
329        public String[] getFormats() {
330                if( formats == null ) { return new String[0]; }
331                return formats.clone();
332        }
333}