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