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 java.util.Map ;
019import java.util.LinkedHashMap ;
020
021import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
022import org.opengion.fukurou.security.HybsCryptography;
023import org.opengion.fukurou.util.Argument;
024import org.opengion.fukurou.util.StringUtil;
025import org.opengion.fukurou.system.LogWriter;
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 のエスケープ記号(&#xZZZZ;)に変換
040 *    getReplaceEscape : HTML のエスケープ記号(&#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         * 初期処理(ファイルオープン、DBオープン等)に使用します。
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                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach
156//                      for( int i=0; i<clmNos.length; i++ ) {
157//                              final String val = (String)data.getValue( clmNos[i] ) ;
158//                              data.setValue( clmNos[i],stAction.change( val ) );
159//                      }
160                        for( final int clmNo : clmNos ) {
161                                final String val = (String)data.getValue( clmNo ) ;
162                                data.setValue( clmNo,stAction.change( val ) );
163                        }
164
165                        if( debug ) { println( "After :" + data.dataLine() ); }         // 5.1.2.0 (2010/01/01) display の条件変更
166                        else if( display ) { println( data.dataLine() ); }              // 5.1.2.0 (2010/01/01) display の条件変更
167                }
168                catch( final Throwable ex ) {
169                        final String errMsg = "row=[" + count + "]" + CR +
170                                                "    data=[" + data + "]" + CR ;
171                        throw new OgRuntimeException( errMsg,ex );
172                }
173                return data;
174        }
175
176        /**
177         * プロセスの終了を行います。最後に一度だけ、呼び出されます。
178         * 終了処理(ファイルクローズ、DBクローズ等)に使用します。
179         *
180         * @param   isOK トータルで、OKだったかどうか[true:成功/false:失敗]
181         */
182        public void end( final boolean isOK ) {
183                keys            = null;         // 変換するカラム名配列のアドレス
184                clmNos          = null;         // 変換するカラム名配列のアドレス
185        }
186
187        /**
188         * プロセスの処理結果のレポート表現を返します。
189         * 処理プログラム名、入力件数、出力件数などの情報です。
190         * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような
191         * 形式で出してください。
192         *
193         * @return   処理結果のレポート
194         */
195        public String report() {
196                // 7.2.9.5 (2020/11/28) PMD:Consider simply returning the value vs storing it in local variable 'XXXX'
197                return "[" + getClass().getName() + "]" + CR
198//              final String report = "[" + getClass().getName() + "]" + CR
199                                + TAB + "Output Count : " + count ;
200
201//              return report ;
202        }
203
204        /**
205         * カラム番号配列を取得します。
206         * 繰返し処理を行う場合に、事前にアドレスでアクセスできるように処理するカラム番号を
207         * キャッシュしておきます。
208         *
209         * @param       data  LineModelオブジェクト
210         */
211        private void makeColumnNos( final LineModel data ) {
212                final String[] clms = StringUtil.csv2Array( keys );
213                final int size = clms.length;
214                clmNos = new int[size];
215                for( int i=0; i<size; i++ ) {
216                        clmNos[i] = data.getColumnNo( clms[i] );
217                }
218        }
219
220        /**
221         * このクラスの使用方法を返します。
222         *
223         * @return      このクラスの使用方法
224         * @og.rtnNotNull
225         */
226        public String usage() {
227                final StringBuilder buf = new StringBuilder( BUFFER_LARGE )
228                        .append( "Process_StringUtil は、上流から受け取ったデータをStringUtilクラスの特定の"  ).append( CR )
229                        .append( "メソッドでデータ変換する、CainProcess インターフェースの実装クラスです。"           ).append( CR )
230                        .append( CR )
231                        .append( "上流(プロセスチェインのデータは上流から下流へと渡されます。)から"                            ).append( CR )
232                        .append( " LineModel を元に、指定のカラムの文字を、変換します。"                                             ).append( CR )
233                        .append( CR )
234                        .append( "現時点で利用できるStringUtil のメソッドは、下記の通りです。"                                  ).append( CR )
235                        .append( "  urlEncode        : UTF-8 で、URLエンコードを行う。"                                                    ).append( CR )
236                        .append( "  rTrim            : 文字列の後ろのスペースを削除"                                                  ).append( CR )
237                        .append( "  htmlFilter       : HTML上のエスケープ文字を変換"                                                        ).append( CR )
238                        .append( "  code39           : CODE39 の 文字列を作成(チェックデジット付き)"                     ).append( CR )
239                        .append( "  getUnicodeEscape : HTML のエスケープ記号(&amp;#xZZZZ;)に変換"                          ).append( CR )
240                        .append( "  getReplaceEscape : HTML のエスケープ記号(&amp;#xZZZZ;)を戻す"                          ).append( CR )
241                        .append( "  spanCut          : 引数からspanタグを取り除く"                                                         ).append( CR )
242                        .append( CR )
243                        .append( "HybsCryptography のメソッドも呼び出せます。"                                                                       ).append( CR )
244                        .append( "  getMD5           : MessageDigestにより、MD5 でハッシュした文字に変換"               ).append( CR )
245                        .append( "  encrypt          : Hybs独自の暗号化を行います(Hybs内部設定の秘密鍵)"           ).append( CR )
246                        .append( "  decrypt          : Hybs独自の復号化を行います(Hybs内部設定の秘密鍵)"           ).append( CR )
247                        .append( CR )
248//                      .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。"    ).append( CR )
249//                      .append( "引数文字列の 『=』 の前後には、空白は挟めません。必ず、-key=value の様に"          ).append( CR )
250//                      .append( "繋げてください。"                                                                                                                             ).append( CR )
251                        .append( PROCESS_PARAM_USAGE )  // 8.5.6.1 (2024/03/29) 継承元使用
252                        .append( CR ).append( CR )
253                        .append( getArgument().usage() ).append( CR );
254
255                return buf.toString();
256        }
257
258        /**
259         * このクラスは、main メソッドから実行できません。
260         *
261         * @param       args    コマンド引数配列
262         */
263        public static void main( final String[] args ) {
264                LogWriter.log( new Process_StringUtil().usage() );
265        }
266
267        /**
268         * インナークラスとして、共通メソッドを定義します(I/Fの代わり)。
269         *
270         * ※ このクラスは継承されるため、final化しません。
271         */
272        private static class StrAction {
273                /**
274                 * デフォルトのコンストラクタ
275                 *
276                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
277                 */
278                public StrAction() {
279                        super();
280                }
281
282                /**
283                 * 引数を変換します。
284                 *
285                 * @param       val             引数
286                 * @return      変換された文字列
287                 */
288                public String change( final String val ) {
289                        return val;
290                }
291        }
292
293        /**
294         * UTF-8 で、URLエンコードを行います。
295         *
296         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
297         */
298        private static final class SU_urlEncode extends StrAction {
299                /**
300                 * デフォルトのコンストラクタ
301                 *
302                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
303                 */
304                public SU_urlEncode() {
305                        super();
306                }
307
308                /**
309                 * 引数を変換します。
310                 *
311                 * @param       val             引数
312                 * @return      変換された文字列
313                 */
314                @Override               // StrAction
315                public String change( final String val ) {
316                        return StringUtil.urlEncode( val );
317                }
318        }
319
320        /**
321         * 文字列の後ろのスペースを削除します。
322         * 注意:'\u0020' (スペース文字) より小さい文字を切り取ります。
323         *
324         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
325         */
326        private static final class SU_rTrim extends StrAction {
327                /**
328                 * デフォルトのコンストラクタ
329                 *
330                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
331                 */
332                public SU_rTrim() {
333                        super();
334                }
335
336                /**
337                 * 引数を変換します。
338                 *
339                 * @param       val             引数
340                 * @return      変換された文字列
341                 */
342                @Override               // StrAction
343                public String change( final String val ) {
344                        return StringUtil.rTrim( val );
345                }
346        }
347
348        /**
349         * HTML上のエスケープ文字を変換します。
350         *
351         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
352         */
353        private static final class SU_htmlFilter extends StrAction {
354                /**
355                 * デフォルトのコンストラクタ
356                 *
357                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
358                 */
359                public SU_htmlFilter() {
360                        super();
361                }
362
363                /**
364                 * 引数を変換します。
365                 *
366                 * @param       val             引数
367                 * @return      変換された文字列
368                 */
369                @Override               // StrAction
370                public String change( final String val ) {
371                        return StringUtil.htmlFilter( val );
372                }
373        }
374
375        /**
376         * CODE39 の 文字列を作成します。(チェックデジット付き)
377         *
378         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
379         */
380        private static final class SU_code39 extends StrAction {
381                /**
382                 * デフォルトのコンストラクタ
383                 *
384                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
385                 */
386                public SU_code39() {
387                        super();
388                }
389
390                /**
391                 * 引数を変換します。
392                 *
393                 * @param       val             引数
394                 * @return      変換された文字列
395                 */
396                @Override               // StrAction
397                public String change( final String val ) {
398                        return StringUtil.code39( val,true );
399                }
400        }
401
402        /**
403         * Unicode文字列の値を HTML のエスケープ記号(&amp;#xZZZZ;)に変換します。
404         *
405         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
406         */
407        private static final class SU_getUnicodeEscape extends StrAction {
408                /**
409                 * デフォルトのコンストラクタ
410                 *
411                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
412                 */
413                public SU_getUnicodeEscape() {
414                        super();
415                }
416
417                /**
418                 * 引数を変換します。
419                 *
420                 * @param       val             引数
421                 * @return      変換された文字列
422                 */
423                @Override               // StrAction
424                public String change( final String val ) {
425                        return StringUtil.getUnicodeEscape( val );
426                }
427        }
428
429        /**
430         * HTML のエスケープ記号(&amp;#xZZZZ;)をUnicode文字列に戻します。
431         *
432         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
433         */
434        private static final class SU_getReplaceEscape extends StrAction {
435                /**
436                 * デフォルトのコンストラクタ
437                 *
438                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
439                 */
440                public SU_getReplaceEscape() {
441                        super();
442                }
443
444                /**
445                 * 引数を変換します。
446                 *
447                 * @param       val             引数
448                 * @return      変換された文字列
449                 */
450                @Override               // StrAction
451                public String change( final String val ) {
452                        return StringUtil.getReplaceEscape( val );
453                }
454        }
455
456        /**
457         * 引数からspanタグを取り除いて返します。
458         *
459         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
460         */
461        private static final class SU_spanCut extends StrAction {
462                /**
463                 * デフォルトのコンストラクタ
464                 *
465                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
466                 */
467                public SU_spanCut() {
468                        super();
469                }
470
471                /**
472                 * 引数を変換します。
473                 *
474                 * @param       val             引数
475                 * @return      変換された文字列
476                 */
477                @Override               // StrAction
478                public String change( final String val ) {
479                        return StringUtil.spanCut( val );
480                }
481        }
482
483        /**
484         * MessageDigestにより、MD5 でハッシュした文字に変換します。
485         *
486         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
487         *
488         * @og.rev 5.2.2.0 (2010/11/01) util.StringUtil から security.HybsCryptography へ移動
489         * @og.rev 8.1.2.0 (2022/03/10) getMD5 メソッドを getHash メソッドに変更
490         *
491         */
492        private static final class SU_getMD5 extends StrAction {
493                /**
494                 * デフォルトのコンストラクタ
495                 *
496                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
497                 */
498                public SU_getMD5() {
499                        super();
500                }
501
502                /**
503                 * 引数を変換します。
504                 *
505                 * @param       val             引数
506                 * @return      変換された文字列
507                 */
508                @Override               // StrAction
509                public String change( final String val ) {
510//                      return HybsCryptography.getMD5( val );                                                          // 8.1.2.0 (2022/03/10) Modify
511                        return HybsCryptography.getHash( "MD5", val );
512                }
513        }
514
515        /**
516         * Hybs独自の暗号化を行います(Hybs内部設定の秘密鍵)
517         *
518         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
519         *
520         * @og.rev 5.2.2.0 (2010/11/01) 新規追加
521         */
522        private static final class SU_encrypt extends StrAction {
523                private HybsCryptography crpt ;
524
525                /**
526                 * デフォルトのコンストラクタ
527                 *
528                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
529                 */
530                public SU_encrypt() {
531                        super();
532                }
533
534                /**
535                 * 引数を変換します。
536                 *
537                 * @param       val             引数
538                 * @return      変換された文字列
539                 */
540                @Override               // StrAction
541                public String change( final String val ) {
542                        if( crpt == null ) {
543                                crpt = new HybsCryptography();
544                        }
545                        return crpt.encrypt( val );
546                }
547        }
548
549        /**
550         * Hybs独自の復号化を行います(Hybs内部設定の秘密鍵)
551         *
552         * acitonで指定されたキーワードで動的に生成され bat 等で使用します。
553         *
554         * @og.rev 5.2.2.0 (2010/11/01) 新規追加
555         */
556        private static final class SU_decrypt extends StrAction {
557                private HybsCryptography crpt ;
558
559                /**
560                 * デフォルトのコンストラクタ
561                 *
562                 * @og.rev 8.5.5.1 (2024/02/29) デフォルトのコンストラクタは必ず用意しておく。
563                 */
564                public SU_decrypt() {
565                        super();
566                }
567
568                /**
569                 * 引数を変換します。
570                 *
571                 * @param       val             引数
572                 * @return      変換された文字列
573                 */
574                @Override               // StrAction
575                public String change( final String val ) {
576                        if( crpt == null ) {
577                                crpt = new HybsCryptography();
578                        }
579                        return crpt.decrypt( val );
580                }
581        }
582}