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