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