    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.plugin.table;
    017
    018import org.opengion.hayabusa.common.HybsSystemException;
    019import org.opengion.hayabusa.db.AbstractTableFilter;
    020import org.opengion.hayabusa.db.DBTableModel;
    021
    022import org.opengion.fukurou.util.ErrorMessage;
    023import org.opengion.fukurou.util.StringUtil;
    024
    025import java.util.Map;
    026import java.util.HashMap;
    027
    028/**
    029 * TableFilter_UNIQ_NAME は、TableFilter インターフェースを継承した、DBTableModel 処理用の
    030 * 実装クラスです。
    031 *
    032 * ここでは、NAME_IN,NAME_OUT,GROUP_KEY,TYPE より、名前を最短ユニーク化します。
    033 * 例えば、氏名で、姓と名で、同姓の場合、姓(名)を付けることで、区別することができます。
    034 *
    035 * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか、BODY 部にCSS形式で記述します。
    036 * 【パラメータ】
    037 *  {
    038 *       NAME_IN   : NAME_CLM  ;    名前のオリジナルのカラムを指定します。(必須)
    039 *       NAME_OUT  : RYAKU_CLM ;    変換後の名前を設定するカラムを指定します。NAME_INと同じでもかまいません。(必須)
    040 *       GROUP_KEY : CDBUMON   ;    名前をユニークにするグループを指定するカラム名を指定します。(選択)
    041 *                                  グループはソートされている必要があります。内部的にはキーブレイク処理します。
    042 *       TYPE      : [1 or 2]  ;    処理の方法を指定します(初期値:1)
    043 *                                    1:姓と名を分けます。重複分は、姓(名) 形式で、ユニークになるまで、名の文字を増やします。
    044 *                                    2:姓と名を分けます。1. と異なるのは、最初に見つけた重複分は、姓 のまま残します。
    045 *  }
    046 *
    047 * 姓名の分離は、全角または、半角のスペースで区切ります。また、重複しなければ、(名)は付きません。
    048 * TYPE="2" の方式は、慣例的に、昔からいる社員は苗字そのままで、後から入社した人にだけ(名)を
    049 * 付けたい場合に、名前を入社年の古い順にならべることで、実現できます。
    050 *
    051 * @og.formSample
    052 * ●形式：
    053 *      ① &lt;og:tableFilter classId="UNIQ_NAME" keys="NAME_IN,NAME_OUT" vals="NAME_CLM,RYAKU_CLM" /&gt;
    054 *
    055 *      ② &lt;og:tableFilter classId="UNIQ_NAME" &gt;
    056 *                 { NAME_IN  : NAME_CLM  ; }
    057 *                 { NAME_OUT : RYAKU_CLM ; }
    058 *         &lt;/og:tableFilter&gt;
    059 *
    060 * @og.rev 5.5.0.3(2012/03/12) 新規作成
    061 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加
    062 *
    063 * @version  0.9.0  2000/10/17
    064 * @author   Kazuhiko Hasegawa
    065 * @since    JDK1.6,
    066 */
    067public class TableFilter_UNIQ_NAME extends AbstractTableFilter {
    068        //* このプログラムのVERSION文字列を設定します。   {@value} */
    069        private static final String VERSION = "5.6.6.1 (2013/07/12)" ;
    070
    071        /**
    072         * keys の整合性チェックを行うための初期設定を行います。
    073         *
    074         * @og.rev 5.6.6.1 (2013/07/12) keys の整合性チェック対応
    075         *
    076         * @param       keysMap keys の整合性チェックを行うための Map
    077         */
    078        @Override
    079        protected void init( final Map<String,String> keysMap ) {
    080                keysMap.put( "NAME_IN"  , "名前のオリジナルのカラムを指定(必須)"         );
    081                keysMap.put( "NAME_OUT" , "変換後の名前を設定するカラムを指定(必須)"       );
    082                keysMap.put( "GROUP_KEY", "名前をユニークにするグループを指定するカラム名を指定"  );
    083                keysMap.put( "TYPE"             , "処理方法を指定(初期値:1) [1 or 2]"     );
    084        }
    085
    086        /**
    087         * DBTableModel処理を実行します。
    088         *
    089         * @og.rev 5.5.2.6 (2012/05/25) protected変数を、private化したため、getterメソッドで取得するように変更
    090         *
    091         * @return 処理結果のDBTableModel
    092         */
    093        public DBTableModel execute() {
    094                DBTableModel table = getDBTableModel();         // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    095
    096                String nameIn   = getValue( "NAME_IN" );
    097                String nameOut  = getValue( "NAME_OUT" );
    098                String groupKey = getValue( "GROUP_KEY" );
    099
    100                int type = StringUtil.nval( getValue( "TYPE" ), 1 );    // NULL　の場合、初期値:1
    101
    102                int inClmNo  = table.getColumnNo( nameIn,false );               // 存在しない場合は、-1 を返す。
    103                int outClmNo = table.getColumnNo( nameOut,false );
    104                int grpClmNo = table.getColumnNo( groupKey,false );
    105
    106                // 必須チェック
    107                if( inClmNo < 0 || outClmNo <0 ) {
    108                        String errMsg = "TableFilter_UNIQ_NAME では、NAME_IN、NAME_OUT　属性は必須です。"
    109                                                + " NAME_IN =" + nameIn
    110                                                + " NAME_OUT=" + nameOut ;
    111                        throw new HybsSystemException( errMsg );
    112                }
    113
    114                // 名前をユニーク化するためのマップ。キーがユニーク化する名前。値は、行番号
    115                Map<String,Integer> nameMap = new HashMap<String,Integer>() ;
    116
    117                String[] data  = null;
    118                int rowCnt = table.getRowCount();
    119                String preKey = null;
    120                int row = 0;
    121                try {
    122                        for( row=0; row<rowCnt; row++ ) {
    123                                data  = table.getValues( row );
    124                                String orgName = data[inClmNo];         // オリジナルの名称
    125
    126                                if( grpClmNo >= 0 && preKey == null ) {
    127                                        preKey = data[grpClmNo];
    128                                        if( preKey == null ) { preKey = ""; }
    129                                }
    130
    131                                if( orgName != null && !orgName.isEmpty() ) {
    132                                        String[] seimei = makeSeiMei( orgName );
    133                                        String sei = seimei[0];
    134                                        String mei = seimei[1];
    135
    136                                        if( nameMap.containsKey( sei ) ) {      // 存在する場合。つまり重複
    137                                                if( type == 1 ) {       // 重複時に最初の分も(名)を付ける。
    138                                                        Integer oldInt = nameMap.get( sei );
    139                                                        if( oldInt != null ) {  // null の場合は、先に重複処理済み
    140                                                                // オリジナルの姓名を取得
    141                                                                String oldName = table.getValue( oldInt.intValue(),inClmNo );
    142                                                                String[] oldSeimei = makeSeiMei( oldName );
    143
    144                                                                String key = makeKey( nameMap , oldSeimei[0] , oldSeimei[1] );
    145                                                                nameMap.put( key, oldInt );             // 変更後のキーと値
    146                                                                nameMap.put( sei, null );               // 比較用に元のキーは残すが値は残さない。
    147                                                        }
    148                                                }
    149
    150                                                String key = makeKey( nameMap , sei , mei );
    151                                                nameMap.put( key, Integer.valueOf( row ) );
    152                                        }
    153                                        else {
    154                                                nameMap.put( sei, Integer.valueOf( row ) );
    155                                        }
    156                                }
    157
    158                                // キーブレイクのチェック
    159                                if( grpClmNo >= 0 && !preKey.equals( data[grpClmNo] ) ) {
    160                                        preKey = data[grpClmNo];
    161                                        if( preKey == null ) { preKey = ""; }
    162
    163                                        for( Map.Entry<String,Integer> nameEnt : nameMap.entrySet() ){
    164                                                Integer orgInt = nameEnt.getValue();
    165                                                if( orgInt != null ) {
    166                                                        int outrow = orgInt.intValue();
    167                                                        table.setValueAt( nameEnt.getKey() , outrow , outClmNo );
    168                                                }
    169                                        }
    170                                        nameMap.clear();
    171                                }
    172                        }
    173                        for( Map.Entry<String,Integer> nameEnt : nameMap.entrySet() ){
    174                                Integer orgInt = nameEnt.getValue();
    175                                if( orgInt != null ) {
    176                                        int outrow = orgInt.intValue();
    177                                        table.setValueAt( nameEnt.getKey() , outrow , outClmNo );
    178                                }
    179                        }
    180                }
    181                catch( RuntimeException ex ) {
    182                        ErrorMessage errMessage = makeErrorMessage( "TableFilter_UNIQ_NAME Error",ErrorMessage.NG );
    183                        errMessage.addMessage( row+1,ErrorMessage.NG,ex.getMessage() );
    184                        errMessage.addMessage( row+1,ErrorMessage.NG,StringUtil.array2csv( data ) );
    185                        errMessage.addMessage( row+1,ErrorMessage.NG,"NAME_IN=[" + nameIn + "]" );
    186                        errMessage.addMessage( row+1,ErrorMessage.NG,"NAME_OUT=[" + nameOut + "]" );
    187                        errMessage.addMessage( row+1,ErrorMessage.NG,"GROUP_KEY=[" + groupKey + "]" );
    188                        errMessage.addMessage( row+1,ErrorMessage.NG,"TYPE=[" + type + "]" );
    189                }
    190                return table;
    191        }
    192
    193        /**
    194         * オリジナルの姓名から、姓と名を分離します。
    195         *
    196         * @param       orgName オリジナルのフルネーム
    197         *
    198         * @return 姓と名の分割結果
    199         */
    200        private String[] makeSeiMei( final String orgName ) {
    201                String[] seimei = new String[2];
    202
    203                int adrs = orgName.indexOf( ' ' );
    204                if( adrs < 0 ) { adrs = orgName.indexOf( '　' ); }
    205                if( adrs < 0 ) {
    206                        seimei[0] = orgName.trim();
    207                        seimei[1] = "";
    208                }
    209                else {
    210                        seimei[0] = orgName.substring( 0,adrs ).trim();
    211                        seimei[1] = orgName.substring( adrs+1 ).trim();
    212                }
    213
    214                return seimei ;
    215        }
    216
    217        /**
    218         * マップに存在しないキーを作成します。マップへの登録は、行いません。
    219         *
    220         * @param       nameMap 過去に登録されている名前キーのマップ
    221         * @param       sei             オリジナルの姓
    222         * @param       mei             オリジナルの名
    223         *
    224         * @return      新しく作成されたキー
    225         */
    226        private String makeKey( final Map<String,Integer> nameMap , final String sei , final String mei ) {
    227                String key = null;
    228
    229                boolean flag = true;    // 未処理フラグ
    230                for( int i=1; i<=mei.length(); i++ ) {
    231                        key = sei + "(" + mei.substring(0,i) + ")" ;
    232                        if( ! nameMap.containsKey( key ) ) {    // 存在しない
    233                                flag = false;
    234                                break;
    235                        }
    236                }
    237                if( flag ) {
    238                        for( int i=1; i<10; i++ ) {
    239                                key = sei + mei + "("  + i  + ")" ;
    240                                if( ! nameMap.containsKey( key ) ) {    // 存在しない
    241                                        break;
    242                                }
    243                        }
    244                }
    245
    246                return key ;
    247        }
    248}