    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.hayabusa.html;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.db.DBTableModel;
    020import org.opengion.fukurou.security.URLHashMap;
    021import org.opengion.fukurou.util.StringUtil;
    022import org.opengion.fukurou.util.Attributes;
    023import org.opengion.fukurou.util.XHTMLTag;
    024import org.opengion.fukurou.model.Formatter;
    025
    026import java.util.Map;
    027import java.util.HashMap;
    028import java.util.List;
    029import java.util.ArrayList;
    030import java.util.Arrays ;
    031
    032/**
    033 * ViewLink インターフェース の実装オブジェクトです。
    034 * これを,共通のスーパークラスとして 各種表示フォーム(例：HTML表示等)に使います。
    035 *
    036 * このクラスは、setter/getterメソッドのデフォルト実装を提供しています。
    037 * 各種表示フォームに対応したサブクラス上で, create() をオーバーライドして下さい。
    038 *
    039 * @og.rev 2.1.0.3 (2002/11/08) エンコードの開始/終了アドレスを求める処理の修正
    040 * @og.rev 4.0.0.0 (2005/08/31) 同一カラムの複数登録を許可します。
    041 * @og.group 画面表示
    042 *
    043 * @version  4.0
    044 * @author   Kazuhiko Hasegawa
    045 * @since    JDK5.0,
    046 */
    047public class ViewLink_LINK implements ViewMarker {
    048        private static final String REQ_KEY = HybsSystem.URL_HASH_REQ_KEY ;
    049
    050        private static final int ACCS_LVL = HybsSystem.sysInt( "URL_ACCESS_SECURITY_LEVEL" );
    051
    052        private List<Attributes>                markData        = null;         // 4.0.0 (2005/08/31)
    053        private Map<Integer,Formatter>  formMap         = new HashMap<Integer,Formatter>();
    054        private DBTableModel            table       = null;
    055        private int[]                           markCmlNo       = null;
    056        private int[]                           isMark          = null;
    057        // 2.1.0.3 (2002/11/08) エンコードの開始/終了アドレスを求める処理の修正
    058        private int[]               encodeIn    = null;         // 初期値:範囲外
    059        private int[]               encodeOut   = null;         // 初期値:範囲外
    060        private static final int        MARK_NULL   = -1;               // リンク未設定
    061        private static final int        MARK_TRUE   = 1;                // リンク作成
    062        private static final int        MARK_FALSE  = 0;                // リンク作成せず
    063        // 3.5.2.0 (2003/10/20)
    064        private String[]                        markKey         = null;
    065        private String[]                        markLists       = null;
    066        private int[]                           markListNo      = null;
    067
    068        private boolean[]                       useURLCheck      = null;        // 4.3.7.1 (2009/06/08)
    069        private String[]                        urlCheckUser = null;    // 4.3.7.1 (2009/06/08)
    070        private long[]                          urlCheckTime = null;    // 4.3.7.1 (2009/06/08)
    071        private boolean[]                       useHrefEncode= null;    // 6.0.2.0 (2014/08/29)
    072
    073        private Map<Integer,List<Integer>>      clmMap  = new HashMap<Integer,List<Integer>>(); // 4.0.0 (2005/08/31)
    074
    075        /**
    076         * 内容をクリア(初期化)します。
    077         *
    078         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
    079         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
    080         * @og.rev 3.5.6.1 (2004/06/25) formMap属性を追加
    081         * @og.rev 4.3.7.1 (2009/06/08) URLチェック属性追加
    082         * @og.rev 6.0.2.0 (2014/08/29) useHrefEncode属性追加
    083         */
    084        public void clear() {
    085                markData        = null;         // 4.0.0 (2005/08/31)
    086                formMap         = new HashMap<Integer,Formatter>();
    087                table       = null;
    088                isMark      = null;
    089                encodeIn    = null;
    090                encodeOut   = null;
    091                markKey         = null;
    092                markLists       = null;
    093                markListNo      = null;
    094                clmMap          = new HashMap<Integer,List<Integer>>(); // 4.0.0 (2005/08/31)
    095                useURLCheck  = null;    // 4.3.7.1 (2009/06/08)
    096                urlCheckUser = null;    // 4.3.7.1 (2009/06/08)
    097                urlCheckTime = null;    // 4.3.7.1 (2009/06/08)
    098                useHrefEncode= null;    // 6.0.2.0 (2014/08/29)
    099        }
    100
    101        /**
    102         * カラムに対するリンクアトリビュートをセットします。
    103         *
    104         * @og.rev 3.1.0.0 (2003/03/20) Hashtable を使用している箇所で、非同期でも構わない箇所を、HashMap に置換え。
    105         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
    106         * @og.rev 4.0.0.0 (2005/08/31) 同一カラムの複数登録を許可します。
    107         *
    108         * @param       attri   リンクアトリビュート
    109         */
    110        public void addAttribute( final Attributes attri ) {
    111                if( markData == null ) { markData = new ArrayList<Attributes>(); }
    112                markData.add( attri );
    113        }
    114
    115        /**
    116         * 内部に DBTableModel をセットします。
    117         *
    118         * @og.rev 2.1.0.3 (2002/11/08) エンコードの開始/終了アドレスを求める処理の修正
    119         * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。
    120         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
    121         * @og.rev 3.5.5.0 (2004/03/12) xlink 属性によるリンク情報作成方法の分岐を追加
    122         * @og.rev 3.5.6.1 (2004/06/25) DBTableModel の再設定に対応。
    123         * @og.rev 3.5.6.2 (2004/07/05) linkFormat をパラメータで取得するように変更。
    124         * @og.rev 3.8.1.1 (2005/11/21) linkFormat が "[","]" をエンコードしてしまった場合に元に戻します。
    125         * @og.rev 4.0.0.0 (2005/08/31) 同一カラムの複数登録を許可します。
    126         * @og.rev 4.3.7.1 (2009/06/08) URLチェック機能追加
    127         * @og.rev 6.0.2.0 (2014/08/29) useHrefEncode属性追加
    128         *
    129         * @param  tbl DBTableModelオブジェクト
    130         */
    131        public void setDBTableModel( final DBTableModel tbl ) {
    132                table   = tbl;
    133                int     count           = markData.size();                      // 4.0.0 (2005/08/31)
    134
    135                isMark          = new int[ count ];
    136                markKey         = new String[ count ];
    137                markCmlNo       = new int[ count ];
    138                markLists       = new String[ count ];
    139                markListNo      = new int[ count ];
    140                encodeIn    = new int[ count ];
    141                encodeOut   = new int[ count ];
    142                useURLCheck   = new boolean[ count ];   // 4.3.7.1 (2009/06/08)
    143                urlCheckUser  = new String[ count ];    // 4.3.7.1 (2009/06/08)
    144                urlCheckTime  = new long[ count ];              // 4.3.7.1 (2009/06/08)
    145                useHrefEncode = new boolean[ count ];   // 6.0.2.0 (2014/08/29)
    146
    147                Arrays.fill( isMark,MARK_FALSE );               // リンクの表示可否
    148                Arrays.fill( markCmlNo,-1 );                    // リンクの可否を判断するカラム番号
    149                Arrays.fill( encodeIn ,10000 );                 // 初期値:範囲外
    150                Arrays.fill( encodeOut,-1 );                    // 初期値:範囲外
    151                Arrays.fill( useURLCheck, false );              // 4.3.7.1 (2009/06/08)
    152                Arrays.fill( urlCheckTime, 0L );                // 4.3.7.1 (2009/06/08)
    153                Arrays.fill( useHrefEncode, false );    // 6.0.2.0 (2014/08/29) 決め打ちに近いがとりあえず初期化は false
    154
    155                // 4.0.0 (2005/08/31) 同一カラムの複数登録を許可します。
    156                for( int intKey=0; intKey<count; intKey++ ) {
    157                        Attributes attri = markData.get( intKey );
    158
    159                        String column = attri.get( "column" );
    160                        int clm = table.getColumnNo( column );
    161                        List<Integer> list = clmMap.get( clm );
    162                        if( list == null ) { list = new ArrayList<Integer>(); }
    163                        list.add( intKey );
    164                        clmMap.put( clm,list );
    165
    166                        String linkFormat = attri.get( "linkFormat" );
    167                        linkFormat = StringUtil.replace( linkFormat,"%5B","[" );        // 3.8.1.1 (2005/11/21)
    168                        linkFormat = StringUtil.replace( linkFormat,"%5D","]" );        // 3.8.1.1 (2005/11/21)
    169
    170                        Formatter formatter = new Formatter( table );
    171                        formatter.setFormat( linkFormat );
    172                        formMap.put( intKey, formatter );
    173
    174                        // URLエンコード用の範囲設定。この範囲内のデータをURLエンコードする。
    175                        String[] format = formatter.getFormat();
    176                        boolean findHref = false;
    177                        for( int j=0; j<format.length; j++ ) {
    178                                if( format[j] != null && format[j].indexOf( "href" ) >= 0 ) { findHref = true; }
    179                                if( findHref && format[j].indexOf( '?' ) >= 0   ) { encodeIn[intKey]  = j; }
    180                                if( findHref && format[j].indexOf( "\" " ) >= 0 ) { encodeOut[intKey] = j; findHref = false; }
    181                        }
    182
    183                        // 4.3.7.1 (2009/06/08)
    184                        useURLCheck[intKey]  = StringUtil.nval( attri.get( "useURLCheck"  ), false );
    185                        urlCheckUser[intKey] = StringUtil.nval( attri.get( "urlCheckUser" ), null );
    186                        urlCheckTime[intKey] = StringUtil.nval( attri.get( "urlCheckTime" ), 0L );
    187                        useHrefEncode[intKey]= StringUtil.nval( attri.get( "useHrefEncode"), false );   // 6.0.2.0 (2014/08/29)
    188                        makeOnLinkFormat( intKey,attri );
    189                }
    190        }
    191
    192        /**
    193         * 指定の行列に対するマーカー文字列を返します。
    194         * この値は,すでにマーカー文字列処理されている為, RendererValue で
    195         * 変換する必要はありません。
    196         * 引数の value はそのカラムの値として利用されます。この値は、修飾済みの
    197         * 値を与えることが可能です。
    198         *
    199         * @og.rev 2.1.0.3 (2002/11/08) エンコードの開始/終了アドレスを求める処理の修正
    200         * @og.rev 3.0.0.0 (2002/12/25) URLEncoder.encode を StringUtil#urlEncode に置換え
    201         * @og.rev 3.0.0.1 (2003/02/14) リンクの引数部分に、RendererValue が適用される箇所を修正
    202         * @og.rev 3.0.0.1 (2003/02/14) リンクの引数部分に、RendererValue が適用される箇所を修正
    203         * @og.rev 3.5.6.1 (2004/06/25) formMap属性を使用します。
    204         * @og.rev 3.7.0.3 (2005/03/01) "{I}" 文字列に、行番号(row)を割り当てます。
    205         * @og.rev 3.8.5.0 (2006/03/20) "{I}" ⇒ "%7BI%7D" として、行番号(row)を割り当てます。
    206         * @og.rev 4.3.7.1 (2009/06/08) URLチェック機能追加
    207         * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
    208         * @og.rev 5.2.3.0 (2010/12/01) URLのハッシュ化/暗号化を行います。
    209         * @og.rev 6.0.2.0 (2014/08/29) useHrefEncode属性追加
    210         *
    211         * @param   row 指定の行
    212         * @param   clm 指定の列
    213         * @param   value カラムの値
    214         *
    215         * @return  row行，colum列 のマーカー文字列
    216         */
    217        public String getMarkerString( final int row,final int clm,final String value ) {
    218                int intKey = isOnLink(row,clm) ;
    219                if( intKey < 0 ) { return value; }
    220
    221                Formatter formatter = formMap.get( intKey );
    222                int[]    clmNo  = formatter.getClmNos();
    223                String[] format = formatter.getFormat();
    224
    225                StringBuilder strLink = new StringBuilder( HybsSystem.BUFFER_LARGE );
    226                int j=0;
    227                String val ;
    228                for( ; j<clmNo.length; j++ ) {
    229                        strLink.append( format[j] );
    230                        if( encodeIn[intKey] <= j && j < encodeOut[intKey] ) {          // encode範囲内
    231//                              val = formatter.getValue(row,clmNo[j]);
    232                                val = StringUtil.urlEncode( formatter.getValue(row,clmNo[j]) );
    233//                              strLink.append( StringUtil.urlEncode( val ) );
    234                        }
    235                        else if( clm == clmNo[j] ) {
    236                                val = value;
    237                                if( useHrefEncode[intKey] && val != null ) {                                            // 6.0.2.0 (2014/08/29) useHrefEncode属性追加
    238                                        val = val.replaceAll( "%","%25" ).replaceAll( ";","%3B" );              // 先に % の変換をしないとまずい。
    239                                }
    240//                              strLink.append( value );
    241                        }
    242                        else {                                                                                                          // encode範囲外
    243                                val = formatter.getValue(row,clmNo[j]);
    244                                if( useHrefEncode[intKey] && val != null ) {                                            // 6.0.2.0 (2014/08/29) useHrefEncode属性追加
    245                                        val = val.replaceAll( "%","%25" ).replaceAll( ";","%3B" );              // 先に % の変換をしないとまずい。
    246                                }
    247//                              strLink.append( val );
    248                        }
    249                        strLink.append( val );
    250                }
    251                strLink.append( format[j] );
    252
    253                // 3.8.5.0 (2006/03/27) "{I}" と そのエンコード文字 "%7BI%7D" に、行番号(row)を割り当てます。
    254                String rtn = strLink.toString();
    255                String sRow = String.valueOf( row );
    256                rtn = StringUtil.replace( rtn,"{I}",sRow );
    257                rtn = StringUtil.replace( rtn,"%7BI%7D",sRow );
    258
    259                // 4.3.7.1 (2009/06/08)
    260                if( useURLCheck[intKey] ) {
    261                        // 4.3.7.4 (2009/07/01)
    262                        rtn = XHTMLTag.embedURLCheckKey( rtn, HybsSystem.URL_CHECK_KEY, urlCheckUser[intKey], urlCheckTime[intKey] );
    263                }
    264
    265                // 5.2.3.0 (2010/12/01) URLのハッシュ化/暗号化
    266                if( ACCS_LVL == 2 ) {
    267                        // ACCS_LVL == 2 の場合は、外部のみ処理するので、extOnly=true をセットする。
    268                        rtn = URLHashMap.makeUrlChange( rtn,REQ_KEY,true );
    269                }
    270                else if( ACCS_LVL == 3 ) {
    271                        rtn = URLHashMap.makeUrlChange( rtn,REQ_KEY,false );
    272                }
    273
    274                return rtn ;
    275        }
    276
    277        /**
    278         * リンクを張る/張らないの指定カラム番号を求めます。
    279         * また、int[列番号] isMark を初期化します。
    280         *
    281         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
    282         *
    283         * @param       intKey  カラムキーの番号
    284         * @param       attri   アトリビュート
    285         */
    286        private void makeOnLinkFormat( final int intKey,final Attributes attri ) {
    287                String onMark   = attri.get( "onLink" );
    288                String markList = attri.get( "markList" );
    289
    290                // 3.5.6.0 (2004/06/18) nullポインタの参照外しバグの対応
    291                // このロジックで値が設定済みであれば、以下の処理は不要である。
    292                isMark[intKey] = MARK_NULL;
    293                if( onMark == null || onMark.length() == 0 ||
    294                        markList == null || markList.length() == 0 ) {
    295                                isMark[intKey] = MARK_FALSE;
    296                                return ;        // 3.5.6.0 (2004/06/18)
    297                }
    298                else if( onMark.charAt( 0 ) != '[' && markList.charAt( 0 ) != '[' ) {
    299                        isMark[intKey] = ( markList.indexOf( onMark ) >= 0 ) ? MARK_TRUE : MARK_FALSE;
    300                        return ;        // 3.5.6.0 (2004/06/18)
    301                }
    302
    303                if( onMark.charAt( 0 ) == '[' ) {
    304                        markCmlNo[intKey] = table.getColumnNo( onMark.substring( 1,onMark.length()-1 ));
    305                }
    306                else {
    307                        markCmlNo[intKey]  = -1;
    308                        markKey[intKey]    = onMark ;
    309                }
    310
    311                if( markList.charAt( 0 ) == '[' ) {
    312                        markListNo[intKey] = table.getColumnNo( markList.substring( 1,markList.length()-1 ));
    313                }
    314                else {
    315                        markListNo[intKey] = -1;
    316                        markLists[intKey] = markList;
    317                }
    318        }
    319
    320        /**
    321         * リンクを張るかどうかを判断します。
    322         * int[列番号] isMark には、 未設定 FALSE TRUE の状態を持っており、
    323         * 列でリンクを張る状態が固定の場合(例えば,onLink属性がデフォルト "true" の場合)
    324         * カラムに関係なく、同じ値を返すときに、使用します。
    325         *
    326         * @og.rev 3.5.2.0 (2003/10/20) markLists,markListNo,markKey属性を追加
    327         * @og.rev 3.5.4.0 (2003/11/25) onMark ,markList が null(またはゼロストリング)の場合は、false とする。
    328         * @og.rev 4.0.0.0 (2005/08/31) 同一カラムの複数登録を許可します。
    329         *
    330         * @param       row     列番号
    331         * @param       clm     カラムキーの名称
    332         *
    333         * @return      処理するリスト番号、-1 の場合は、該当なし
    334         */
    335        private int isOnLink( final int row,final int clm ) {
    336
    337                List<Integer> list = clmMap.get( clm );
    338                if( list == null ) { return -1; }
    339
    340                for( int i=0; i<list.size(); i++ ) {
    341                        int intKey = list.get( i );
    342                        if( isMark[intKey] != MARK_NULL ) {
    343                                if( isMark[intKey] == MARK_TRUE ) { return intKey; }
    344                                else { continue; }
    345                        }
    346
    347                        String onMark ;
    348                        if( markCmlNo[intKey] < 0 ) { onMark = markKey[intKey] ; }
    349                        else { onMark = table.getValue( row,markCmlNo[intKey] ); }
    350
    351                        // 3.5.4.0 (2003/11/25) 追加
    352                        if( onMark == null || onMark.length() == 0 ) { continue; }
    353
    354                        String markList ;
    355                        if( markListNo[intKey] < 0 ) { markList = markLists[intKey] ; }
    356                        else { markList = table.getValue( row,markListNo[intKey] ); }
    357
    358                        // 3.5.4.0 (2003/11/25) 修正
    359                        if( markList == null || markList.length() == 0 ) { continue; }
    360
    361                        if( markList.indexOf( onMark ) >= 0 ) { return intKey; }
    362                }
    363                return -1;
    364        }
    365}