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