    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.process;
    017
    018import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    019import org.opengion.fukurou.security.HybsCryptography;
    020import org.opengion.fukurou.util.Argument;
    021import org.opengion.fukurou.util.StringUtil;
    022import org.opengion.fukurou.system.LogWriter;
    023
    024import java.util.Map ;
    025import java.util.LinkedHashMap ;
    026
    027/**
    028 * Process_StringUtil は、上流から受け取ったデータをStringUtilクラスの特定の
    029 * メソッドでデータ変換する、CainProcess インターフェースの実装クラスです。
    030 *
    031 * 上流(プロセスチェインのデータは上流から下流へと渡されます。)から
    032 *  LineModel を元に、指定のカラムの文字を、変換します。
    033 *
    034 * 現時点で利用できるStringUtil のメソッドは、下記の通りです。
    035 *    urlEncode        : UTF-8 で、URLエンコードを行う。
    036 *    rTrim            : 文字列の後ろのスペースを削除
    037 *    htmlFilter       : HTML上のエスケープ文字を変換
    038 *    code39           : CODE39 の 文字列を作成(チェックデジット付き)
    039 *    getUnicodeEscape : HTML のエスケープ記号(&amp;#xZZZZ;)に変換
    040 *    getReplaceEscape : HTML のエスケープ記号(&amp;#xZZZZ;)を戻す
    041 *    spanCut          : 引数からspanタグを取り除く
    042 *
    043 * HybsCryptography のメソッドも呼び出せます。
    044 *    getMD5           : MessageDigestにより、MD5 でハッシュした文字に変換
    045 *    encrypt          : Hybs独自の暗号化を行います(Hybs内部設定の秘密鍵)
    046 *    decrypt          : Hybs独自の復号化を行います(Hybs内部設定の秘密鍵)
    047 *
    048 * action=getMD5 等は、動的にメソッドを生成して bat 等で使用します。
    049 *
    050 * 引数文字列中にスペースを含む場合は、ダブルコーテーション("") で括って下さい。
    051 * 引数文字列の 『=』の前後には、スペースは挟めません。必ず、-key=value の様に
    052 * 繋げてください。
    053 *
    054 * @og.formSample
    055 *  Process_StringUtil -action=getMD5|encrypt|decrypt|code39|getUnicodeEscape|getReplaceEscape|･･･ -keys=AA,BB,CC
    056 *
    057 *     -action=ESC|REV        ：StringUtilクラスの特定のメソッド名を指定します(必須)。
    058 *                              urlEncode|rTrim|htmlFilter|getMD5|code39|getUnicodeEscape|getReplaceEscape|spanCut
    059 *     -keys=AA,BB,CC         ：変換するカラムをCSV形式で複数指定できます(必須)。
    060 *   [ -display=[false/true]] ：結果を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない])
    061 *   [ -debug=[false/true]  ] ：デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない])
    062 *
    063 * @og.rev 5.0.0.2 (2009/09/15) 新規クラス作成
    064 *
    065 * @version  0.9.0  2004/02/27
    066 * @author   Kazuhiko Hasegawa
    067 * @since    JDK5.0,
    068 */
    069public class Process_StringUtil extends AbstractProcess implements ChainProcess {
    070
    071        private static final String STR_ACTION_BASE = "org.opengion.fukurou.process.Process_StringUtil$SU_" ;
    072
    073        private String          keys            ;               // 変換するカラム名配列のアドレス
    074        private int[]           clmNos          ;               // 変換するカラム名配列のアドレス
    075        private boolean         display         ;               // 表示しない
    076        private boolean         debug           ;               // 5.7.3.0 (2014/02/07) デバッグ情報
    077
    078        private boolean         firstRow        = true; // 最初の一行目
    079        private int                     count           ;
    080        private StrAction       stAction        ;               // Ver 5.0.0.2 (2009/09/15)
    081
    082        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
    083        private static final Map<String,String> MUST_PROPARTY   ;               // ［プロパティ］必須チェック用 Map
    084        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
    085        private static final Map<String,String> USABLE_PROPARTY ;               // ［プロパティ］整合性チェック Map
    086
    087        static {
    088                MUST_PROPARTY = new LinkedHashMap<>();
    089                MUST_PROPARTY.put( "action",            "StringUtilの特定のメソッドを指定します(必須)" +
    090                                                                                CR + "urlEncode , rTrim , htmlFilter , getMD5 , encrypt , decrypt , code39 , getUnicodeEscape , getReplaceEscape , spanCut" );
    091
    092                MUST_PROPARTY.put( "keys",              "変換するカラムをCSV形式で複数指定できます(必須)。" );
    093
    094                USABLE_PROPARTY = new LinkedHashMap<>();
    095                USABLE_PROPARTY.put( "display", "結果を標準出力に表示する(true)かしない(false)か" +
    096                                                                                CR + " (初期値:false[表示しない])" );
    097                USABLE_PROPARTY.put( "debug",   "デバッグ情報を標準出力に表示する(true)かしない(false)か" +
    098                                                                                CR + "(初期値:false:表示しない)" );             // 5.7.3.0 (2014/02/07) デバッグ情報
    099        }
    100
    101        /**
    102         * デフォルトコンストラクター。
    103         * このクラスは、動的作成されます。デフォルトコンストラクターで、
    104         * super クラスに対して、必要な初期化を行っておきます。
    105         *
    106         */
    107        public Process_StringUtil() {
    108                super( "org.opengion.fukurou.process.Process_StringUtil",MUST_PROPARTY,USABLE_PROPARTY );
    109        }
    110
    111        /**
    112         * プロセスの初期化を行います。初めに一度だけ、呼び出されます。
    113         * 初期処理(ファイルオープン、ＤＢオープン等)に使用します。
    114         *
    115         * @param   paramProcess データベースの接続先情報などを持っているオブジェクト
    116         */
    117        public void init( final ParamProcess paramProcess ) {
    118                final Argument arg = getArgument();
    119
    120                keys            = arg.getProparty( "keys",keys );
    121                display         = arg.getProparty( "display",display );
    122                debug           = arg.getProparty("debug",debug);                               // 5.7.3.0 (2014/02/07) デバッグ情報
    123
    124                final String act        = arg.getProparty( "action" );
    125
    126                stAction        = (StrAction)StringUtil.newInstance( STR_ACTION_BASE + act );
    127        }
    128
    129        /**
    130         * 引数の LineModel を処理するメソッドです。
    131         * 変換処理後の LineModel を返します。
    132         * 後続処理を行わない場合(データのフィルタリングを行う場合)は、
    133         * null データを返します。つまり、null データは、後続処理を行わない
    134         * フラグの代わりにも使用しています。
    135         * なお、変換処理後の LineModel と、オリジナルの LineModel が、
    136         * 同一か、コピー(クローン)かは、各処理メソッド内で決めています。
    137         * ドキュメントに明記されていない場合は、副作用が問題になる場合は、
    138         * 各処理ごとに自分でコピー(クローン)して下さい。
    139         *
    140         * @param   data        オリジナルのLineModel
    141         *
    142         * @return      処理変換後のLineModel
    143         */
    144        @Override       // ChainProcess
    145        public LineModel action( final LineModel data ) {
    146                count++ ;
    147                try {
    148                        if( firstRow ) {
    149                                makeColumnNos( data );
    150                                firstRow = false;
    151                                if( display ) { println( data.nameLine() ); }           // 5.7.3.0 (2014/02/07) デバッグ情報
    152                        }
    153
    154                        if( debug ) { println( "Before:" + data.dataLine() ); }         // 5.1.2.0 (2010/01/01) display の条件変更
    155                        for( int i=0; i<clmNos.length; i++ ) {
    156                                final String val = (String)data.getValue( clmNos[i] ) ;
    157                                data.setValue( clmNos[i],stAction.change( val ) );
    158                        }
    159
    160                        if( debug ) { println( "After :" + data.dataLine() ); }         // 5.1.2.0 (2010/01/01) display の条件変更
    161                        else if( display ) { println( data.dataLine() ); }              // 5.1.2.0 (2010/01/01) display の条件変更
    162                }
    163                catch( final Throwable ex ) {
    164                        final String errMsg = "row=[" + count + "]" + CR +
    165                                                "    data=[" + data + "]" + CR ;
    166                        throw new OgRuntimeException( errMsg,ex );
    167                }
    168                return data;
    169        }
    170
    171        /**
    172         * プロセスの終了を行います。最後に一度だけ、呼び出されます。
    173         * 終了処理(ファイルクローズ、ＤＢクローズ等)に使用します。
    174         *
    175         * @param   isOK トータルで、OKだったかどうか[true:成功/false:失敗]
    176         */
    177        public void end( final boolean isOK ) {
    178                keys            = null;         // 変換するカラム名配列のアドレス
    179                clmNos          = null;         // 変換するカラム名配列のアドレス
    180        }
    181
    182        /**
    183         * プロセスの処理結果のレポート表現を返します。
    184         * 処理プログラム名、入力件数、出力件数などの情報です。
    185         * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような
    186         * 形式で出してください。
    187         *
    188         * @return   処理結果のレポート
    189         */
    190        public String report() {
    191                // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX'
    192                return "[" + getClass().getName() + "]" + CR
    193//              final String report = "[" + getClass().getName() + "]" + CR
    194                                + TAB + "Output Count : " + count ;
    195
    196//              return report ;
    197        }
    198
    199        /**
    200         * カラム番号配列を取得します。
    201         * 繰返し処理を行う場合に、事前にアドレスでアクセスできるように処理するカラム番号を
    202         * キャッシュしておきます。
    203         *
    204         * @param       data  LineModelオブジェクト
    205         */
    206        private void makeColumnNos( final LineModel data ) {
    207                final String[] clms = StringUtil.csv2Array( keys );
    208                final int size = clms.length;
    209                clmNos = new int[size];
    210                for( int i=0; i<size; i++ ) {
    211                        clmNos[i] = data.getColumnNo( clms[i] );
    212                }
    213        }
    214
    215        /**
    216         * このクラスの使用方法を返します。
    217         *
    218         * @return      このクラスの使用方法
    219         * @og.rtnNotNull
    220         */
    221        public String usage() {
    222                final StringBuilder buf = new StringBuilder( BUFFER_LARGE )
    223                        .append( "Process_StringUtil は、上流から受け取ったデータをStringUtilクラスの特定の"  ).append( CR )
    224                        .append( "メソッドでデータ変換する、CainProcess インターフェースの実装クラスです。"   ).append( CR )
    225                        .append( CR )
    226                        .append( "上流(プロセスチェインのデータは上流から下流へと渡されます。)から"                            ).append( CR )
    227                        .append( " LineModel を元に、指定のカラムの文字を、変換します。"                                             ).append( CR )
    228                        .append( CR )
    229                        .append( "現時点で利用できるStringUtil のメソッドは、下記の通りです。"                                  ).append( CR )
    230                        .append( "  urlEncode        : UTF-8 で、URLエンコードを行う。"                                                    ).append( CR )
    231                        .append( "  rTrim            : 文字列の後ろのスペースを削除"                                                  ).append( CR )
    232                        .append( "  htmlFilter       : HTML上のエスケープ文字を変換"                                                        ).append( CR )
    233                        .append( "  code39           : CODE39 の 文字列を作成(チェックデジット付き)"                     ).append( CR )
    234                        .append( "  getUnicodeEscape : HTML のエスケープ記号(&amp;#xZZZZ;)に変換"                          ).append( CR )
    235                        .append( "  getReplaceEscape : HTML のエスケープ記号(&amp;#xZZZZ;)を戻す"                          ).append( CR )
    236                        .append( "  spanCut          : 引数からspanタグを取り除く"                                                         ).append( CR )
    237                        .append( CR )
    238                        .append( "HybsCryptography のメソッドも呼び出せます。"                                                                       ).append( CR )
    239                        .append( "  getMD5           : MessageDigestにより、MD5 でハッシュした文字に変換"               ).append( CR )
    240                        .append( "  encrypt          : Hybs独自の暗号化を行います(Hybs内部設定の秘密鍵)"           ).append( CR )
    241                        .append( "  decrypt          : Hybs独自の復号化を行います(Hybs内部設定の秘密鍵)"           ).append( CR )
    242                        .append( CR )
    243                        .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。"    ).append( CR )
    244                        .append( "引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に"           ).append( CR )
    245                        .append( "繋げてください。"                                                                                                                             ).append( CR )
    246                        .append( CR ).append( CR )
    247                        .append( getArgument().usage() ).append( CR );
    248
    249                return buf.toString();
    250        }
    251
    252        /**
    253         * このクラスは、main メソッドから実行できません。
    254         *
    255         * @param       args    コマンド引数配列
    256         */
    257        public static void main( final String[] args ) {
    258                LogWriter.log( new Process_StringUtil().usage() );
    259        }
    260
    261        /**
    262         * インナークラスとして、共通メソッドを定義します(I/Fの代わり)。
    263         *
    264         * ※ このクラスは継承されるため、final化しません。
    265         */
    266        private static class StrAction {
    267                /**
    268                 * 引数を変換します。
    269                 *
    270                 * @param       val             引数
    271                 * @return      変換された文字列
    272                 */
    273                public String change( final String val ) {
    274                        return val;
    275                }
    276        }
    277
    278        /**
    279         * UTF-8 で、URLエンコードを行います。
    280         *
    281         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    282         */
    283        private static final class SU_urlEncode extends StrAction {
    284                /**
    285                 * 引数を変換します。
    286                 *
    287                 * @param       val             引数
    288                 * @return      変換された文字列
    289                 */
    290                @Override
    291                public String change( final String val ) {
    292                        return StringUtil.urlEncode( val );
    293                }
    294        }
    295
    296        /**
    297         * 文字列の後ろのスペースを削除します。
    298         * 注意：'\u0020' (スペース文字) より小さい文字を切り取ります。
    299         *
    300         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    301         */
    302        private static final class SU_rTrim extends StrAction {
    303                /**
    304                 * 引数を変換します。
    305                 *
    306                 * @param       val             引数
    307                 * @return      変換された文字列
    308                 */
    309                @Override
    310                public String change( final String val ) {
    311                        return StringUtil.rTrim( val );
    312                }
    313        }
    314
    315        /**
    316         * HTML上のエスケープ文字を変換します。
    317         *
    318         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    319         */
    320        private static final class SU_htmlFilter extends StrAction {
    321                /**
    322                 * 引数を変換します。
    323                 *
    324                 * @param       val             引数
    325                 * @return      変換された文字列
    326                 */
    327                @Override
    328                public String change( final String val ) {
    329                        return StringUtil.htmlFilter( val );
    330                }
    331        }
    332
    333        /**
    334         * CODE39 の 文字列を作成します。(チェックデジット付き)
    335         *
    336         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    337         */
    338        private static final class SU_code39 extends StrAction {
    339                /**
    340                 * 引数を変換します。
    341                 *
    342                 * @param       val             引数
    343                 * @return      変換された文字列
    344                 */
    345                @Override
    346                public String change( final String val ) {
    347                        return StringUtil.code39( val,true );
    348                }
    349        }
    350
    351        /**
    352         * Unicode文字列の値を HTML のエスケープ記号(&amp;#xZZZZ;)に変換します。
    353         *
    354         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    355         */
    356        private static final class SU_getUnicodeEscape extends StrAction {
    357                /**
    358                 * 引数を変換します。
    359                 *
    360                 * @param       val             引数
    361                 * @return      変換された文字列
    362                 */
    363                @Override
    364                public String change( final String val ) {
    365                        return StringUtil.getUnicodeEscape( val );
    366                }
    367        }
    368
    369        /**
    370         * HTML のエスケープ記号(&amp;#xZZZZ;)をUnicode文字列に戻します。
    371         *
    372         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    373         */
    374        private static final class SU_getReplaceEscape extends StrAction {
    375                /**
    376                 * 引数を変換します。
    377                 *
    378                 * @param       val             引数
    379                 * @return      変換された文字列
    380                 */
    381                @Override
    382                public String change( final String val ) {
    383                        return StringUtil.getReplaceEscape( val );
    384                }
    385        }
    386
    387        /**
    388         * 引数からspanタグを取り除いて返します。
    389         *
    390         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    391         */
    392        private static final class SU_spanCut extends StrAction {
    393                /**
    394                 * 引数を変換します。
    395                 *
    396                 * @param       val             引数
    397                 * @return      変換された文字列
    398                 */
    399                @Override
    400                public String change( final String val ) {
    401                        return StringUtil.spanCut( val );
    402                }
    403        }
    404
    405        /**
    406         * MessageDigestにより、MD5 でハッシュした文字に変換します。
    407         *
    408         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    409         *
    410         * @og.rev 5.2.2.0 (2010/11/01) util.StringUtil から security.HybsCryptography へ移動
    411         * @og.rev 8.1.2.0 (2022/03/10) getMD5 ﾒｿｯﾄﾞを getHash ﾒｿｯﾄﾞに変更
    412         *
    413         */
    414        private static final class SU_getMD5 extends StrAction {
    415                /**
    416                 * 引数を変換します。
    417                 *
    418                 * @param       val             引数
    419                 * @return      変換された文字列
    420                 */
    421                @Override
    422                public String change( final String val ) {
    423//                      return HybsCryptography.getMD5( val );                                                          // 8.1.2.0 (2022/03/10) Modify
    424                        return HybsCryptography.getHash( "MD5", val );
    425                }
    426        }
    427
    428        /**
    429         * Hybs独自の暗号化を行います(Hybs内部設定の秘密鍵)
    430         *
    431         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    432         *
    433         * @og.rev 5.2.2.0 (2010/11/01) 新規追加
    434         */
    435        private static final class SU_encrypt extends StrAction {
    436                private HybsCryptography crpt ;
    437
    438                /**
    439                 * 引数を変換します。
    440                 *
    441                 * @param       val             引数
    442                 * @return      変換された文字列
    443                 */
    444                @Override
    445                public String change( final String val ) {
    446                        if( crpt == null ) {
    447                                crpt = new HybsCryptography();
    448                        }
    449                        return crpt.encrypt( val );
    450                }
    451        }
    452
    453        /**
    454         * Hybs独自の復号化を行います(Hybs内部設定の秘密鍵)
    455         *
    456         * acitonで指定されたｷｰﾜｰﾄﾞで動的に生成され bat 等で使用します。
    457         *
    458         * @og.rev 5.2.2.0 (2010/11/01) 新規追加
    459         */
    460        private static final class SU_decrypt extends StrAction {
    461                private HybsCryptography crpt ;
    462
    463                /**
    464                 * 引数を変換します。
    465                 *
    466                 * @param       val             引数
    467                 * @return      変換された文字列
    468                 */
    469                @Override
    470                public String change( final String val ) {
    471                        if( crpt == null ) {
    472                                crpt = new HybsCryptography();
    473                        }
    474                        return crpt.decrypt( val );
    475                }
    476        }
    477}