    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.taglib;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.hayabusa.resource.GUIInfo;
    021import org.opengion.hayabusa.resource.UserInfo;
    022import org.opengion.hayabusa.resource.FavoriteGUIData;
    023import org.opengion.fukurou.util.XHTMLTag;
    024import org.opengion.fukurou.util.ToString;                                                      // 6.1.1.0 (2015/01/17)
    025import org.opengion.fukurou.util.StringUtil ;                                           // 6.2.2.0 (2015/03/27)
    026
    027import static org.opengion.fukurou.util.StringUtil.nval ;
    028
    029import javax.servlet.http.HttpServletRequest ;
    030import javax.servlet.http.HttpServletResponse;
    031
    032import java.util.Enumeration;
    033import java.util.ArrayList;
    034import java.util.Map;
    035import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
    036
    037import java.io.IOException;
    038
    039/**
    040 * お気に入りリンクを作成するタグです(通常はresult.jspに組込み)。
    041 *
    042 * 画面検索時の引数やユーザー情報を元にして、ダイレクトに再検索できる
    043 * リンクを作成します。このリンクをお気に入り等にセーブしておき、次回検索時にも
    044 * 使用できるようにします。
    045 *
    046 * @og.formSample
    047 * ●形式：&lt;og:favoriteLink direct="true" target="_blank" method="GET" /&gt;
    048 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    049 *
    050 * ●Tag定義：
    051 *   &lt;og:favoriteLink
    052 *       target             【TAG】リンク先の文書を表示させるフレーム、またはウィンドウの名前を指定します(初期値:_blank)
    053 *       direct             【TAG】直接アクセスできる形式のリンクを作成するかどうか[true/false]を指定します(初期値:false)
    054 *       method             【TAG】リンクの作成元となるメソッド[POST/GET/ALL]を指定します(初期値:GET)
    055 *       href               【TAG】リンクを作成する時の転送先アドレスを指定します(初期値:index.jsp)
    056 *       lbl                【TAG】ラベルリソースのラベルIDを指定します
    057 *       linkCache          【TAG】リンクをキャッシュするかどうか[true/false]を指定します(初期値:false)
    058 *       lastQueryRedirect  【TAG】キャッシュされたリンク先に転送するかどうか[true/false]を指定します(初期値:false)
    059 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    060 *       useIcon            【TAG】お気に入りアイコンリンクを作成するかどうか[true/false]を指定します(初期値:false)
    061 *   &gt;   ... Body ...
    062 *   &lt;/og:favoriteLink&gt;
    063 *
    064 * ●使用例：
    065 *    直接お気に入りのリンクを作成する。
    066 *    デフォルト属性を使用(direct="true" target="_blank" method="GET")
    067 *    &lt;og:favoriteLink &gt; Favorite Link &lt;/og:favoriteLink &gt;
    068 *
    069 * @og.group 画面部品
    070 *
    071 * @version  4.0
    072 * @author       Kazuhiko Hasegawa
    073 * @since    JDK5.0,
    074 */
    075public class FavoriteLinkTag extends CommonTagSupport {
    076        /** このプログラムのVERSION文字列を設定します。   {@value} */
    077        private static final String VERSION = "6.4.3.1 (2016/02/12)" ;
    078        private static final long serialVersionUID = 643120160212L ;
    079
    080        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
    081        private static final Map<String,String> LAST_QUERY      = new ConcurrentHashMap<>();    // 6.4.1.1 (2016/01/16) lastQuery → LAST_QUERY  refactoring
    082
    083        private boolean         direct          ;                               // 3.0.0.0 初期値変更
    084        private String          target          = "_blank";             // 3.6.0.7 (2004/11/06)
    085        private String          method          = "GET";
    086        private String          href            = "index.jsp";  // 3.8.8.2 (2007/01/26)
    087        private boolean         linkCache       ;                               // 3.5.5.9 (2004/06/07)
    088        private boolean         redirect        ;                               // 3.5.5.9 (2004/06/07)
    089        private boolean         useIcon         ;                               // 4.1.1.0 (2008/02/13)
    090
    091        /**
    092         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    093         *
    094         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。ボディが存在する場合のみボディが呼ばれる対応。
    095         * @og.rev 3.5.5.9 (2004/06/07) リンクキャッシュより最終画面を転送表示します。
    096         * @og.rev 5.0.0.2 (2009/09/15) xss対応⇒チェックする
    097         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
    098         *
    099         * @return      後続処理の指示
    100         */
    101        @Override
    102        public int doStartTag() {
    103                // 5.0.0.2 (2009/09/15) 強制False
    104                // useXssCheck( false );
    105
    106                // 3.5.5.9 (2004/06/07) リンクキャッシュより最終画面を転送表示
    107                if( redirect ) {
    108                        // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。key,val は、not null 制限。
    109                        final String uid = getUserInfo( "ID" );
    110
    111                        final String page = uid == null ? null : LAST_QUERY.get( uid ) ;
    112
    113                        if( page != null ) {
    114                                final HttpServletResponse response = (HttpServletResponse)pageContext.getResponse();
    115                                final String url = response.encodeRedirectURL( page );
    116                                try {
    117                                        response.sendRedirect( url );
    118                                }
    119                                catch( final IOException ex ) {
    120                                        final String errMsg = "最終画面の転送時のリダイレクトエラー" + toString();
    121                                        throw new HybsSystemException( errMsg,ex );
    122                                }
    123
    124                                return SKIP_BODY ;
    125                        }
    126                }
    127
    128                set( "body",getMsglbl() );
    129                return EVAL_BODY_BUFFERED ;     // Body を評価する。( extends BodyTagSupport 時)
    130        }
    131
    132        /**
    133         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    134         *
    135         * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
    136         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。ボディが存在する場合のみボディが呼ばれる対応。
    137         *
    138         * @return      後続処理の指示(SKIP_BODY)
    139         */
    140        @Override
    141        public int doAfterBody() {
    142
    143                final String label = getBodyString();
    144
    145                if( label != null && label.length() > 0 ) {
    146                        set( "body",label );
    147                }
    148
    149                return SKIP_BODY ;
    150        }
    151
    152        /**
    153         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    154         *
    155         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    156         * @og.rev 4.1.1.0 (2008/0213) お気に入りアイコンリンクの作成
    157         *
    158         * @return      後続処理の指示
    159         */
    160        @Override
    161        public int doEndTag() {
    162                debugPrint();           // 4.0.0 (2005/02/28)
    163
    164                // method による条件判断。
    165                final String requestMethod = ((HttpServletRequest)getRequest()).getMethod();
    166                if( method != null &&
    167                        ( "ALL".equalsIgnoreCase( method ) ||
    168                          method.equalsIgnoreCase( requestMethod ) ) ) {
    169                                // 4.1.1.0 (2008/0213) お気に入りアイコンリンクの作成
    170                                if( useIcon ) {
    171                                        jspPrint( getFavoriteIcon() );
    172                                }
    173                                else {
    174                                        jspPrint( makeTag() );
    175                                }
    176                }
    177
    178                return EVAL_PAGE ;
    179        }
    180
    181        /**
    182         * タグリブオブジェクトをリリースします。
    183         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    184         *
    185         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
    186         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    187         * @og.rev 3.5.5.9 (2004/06/07) linkCache , redirect 属性を追加
    188         * @og.rev 3.6.0.7 (2004/11/06) target 属性の初期値を _new から _blank に変更
    189         * @og.rev 3.8.8.2 (2007/01/26) href 属性を追加
    190         *
    191         */
    192        @Override
    193        protected void release2() {
    194                super.release2();
    195                direct          = false;
    196                target          = "_blank";             // 3.6.0.7 (2004/11/06)
    197                method          = "GET";
    198                href            = "index.jsp";  // 3.8.8.2 (2007/01/26)
    199                linkCache       = false;                // 3.5.5.9 (2004/06/07)
    200                redirect        = false;                // 3.5.5.9 (2004/06/07)
    201        }
    202
    203        /**
    204         * お気に入りリンクを作成します。
    205         *
    206         * @og.rev 3.8.8.2 (2007/01/26) href 属性を追加
    207         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
    208         *
    209         * @return      お気に入りリンクタグ文字列
    210         * @og.rtnNotNull
    211         */
    212        protected String makeTag() {
    213                final HttpServletRequest request = (HttpServletRequest)getRequest();
    214
    215                // ダイレクトリンク時の設定
    216                // リンクの作成
    217                // http://C00000:C00000@hn50g5:8080/dbdef/jsp/index.jsp?GAMENID=xxx&command=NEW&key=val
    218                final StringBuilder link = new StringBuilder( BUFFER_MIDDLE )
    219                        .append( "http://" )
    220                        .append( request.getServerName() ).append( ':' )        // hn50g5:              // 6.0.2.5 (2014/10/31) char を append する。
    221                        .append( request.getServerPort() )                                      // 8823
    222                        .append( request.getContextPath() )                                     // /dbdef
    223                        .append( "/jsp/" );
    224
    225                // 4.0.0 (2005/01/31)
    226                final String direct_jsp  = getGUIInfoAttri( "ADDRESS" ) + "/" + (String)getSessionAttribute( "JSPID" );
    227
    228                final String hrefUrl = link.toString() ;
    229                if( direct ) {
    230                        set( "href" , hrefUrl + direct_jsp );
    231                }
    232                else {
    233                        set( "href" , hrefUrl + href );         // 3.8.8.2 (2007/01/26)
    234                }
    235
    236                set( "target" ,target );
    237                set( "title"  ,getGUIInfoAttri( "LABEL" ) );    // 4.0.0 (2005/01/31)
    238
    239                final String urlEnc = makeUrlEncode( request );
    240
    241                // linkCache による、最終リクエストのアドレスを格納しておきます。
    242                if( linkCache ) {
    243                        // 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。key,val は、not null 制限。
    244                        final String uid = getUserInfo( "ID" );
    245                        if( uid != null ) {
    246                                final String val = hrefUrl + direct_jsp + "?" + urlEnc ;
    247                                LAST_QUERY.put( uid,val );
    248                        }
    249
    250                }
    251
    252                return XHTMLTag.link( getAttributes(),urlEnc ) ;
    253        }
    254
    255        /**
    256         * URLエンコードを行ったリンク情報を作成します。
    257         *
    258         * @og.rev 3.1.0.0 (2003/03/20) Vector を使用している箇所で、非同期でも構わない箇所を、ArrayList に置換え。
    259         * @og.rev 3.1.2.0 (2003/04/07) 画面IDと実画面ディレクトリとの関連見直し(DIRの代りにGAMENIDを渡すように変更)
    260         * @og.rev 3.1.8.0 (2003/05/16) 内部で作成している GAMENID 属性をセットしないように変更。
    261         * @og.rev 4.0.0.0 (2007/07/11) submitTag で作成されたボタンパラメータは、次ページへ転送しません。
    262         * @og.rev 5.0.0.2 (2009/09/15) xssチェック対応
    263         *
    264         * @param       request HttpServletRequestオブジェクト
    265         *
    266         * @return      URLエンコードを行ったリンク情報
    267         * @og.rtnNotNull
    268         */
    269        private String makeUrlEncode( final HttpServletRequest request ) {
    270                final Enumeration<?> enume = request.getParameterNames();               // 4.3.3.6 (2008/11/15) Generics警告対応
    271                final ArrayList<String> v_keys = new ArrayList<>();
    272                final ArrayList<String> v_vals = new ArrayList<>();
    273                while( enume.hasMoreElements() ) {
    274                        final String key = String.valueOf( enume.nextElement() );
    275                        if( key != null && key.startsWith( HybsSystem.NO_XFER_KEY ) ) {
    276                                continue;
    277                        }
    278
    279                        // String val = getRequestValue( key );
    280                        final String val = getRequestValue( key, false ); // 5.0.0.2 (2009/09/15)
    281                        if( val != null && val.length() > 0 ) {
    282                                v_keys.add( key );
    283                                v_vals.add( val );
    284                        }
    285                }
    286
    287                final String[] keys = v_keys.toArray( new String[v_keys.size()] );
    288                final String[] vals = v_vals.toArray( new String[v_vals.size()] );
    289
    290                return XHTMLTag.urlEncode( keys,vals );
    291        }
    292
    293        /**
    294         * お気に入りアイコンを取得します。
    295         *
    296         * @og.rev 4.1.1.0 (2008/02/12) 新規追加
    297         * @og.rev 6.2.2.0 (2015/03/27) BRと\nを相互に変換する処理を追加
    298         * @og.rev 6.2.2.3 (2015/04/10) htmlフィルターに、BR→改行処理機能を追加。
    299         *
    300         * @return      お気に入りアイコンのリンクを返します。
    301         * @og.rtnNotNull
    302         */
    303        private String getFavoriteIcon() {
    304                final GUIInfo guiInfo           = ( GUIInfo )getSessionAttribute( HybsSystem.GUIINFO_KEY );
    305                final String mscVal             = getRequestValue( "MSC" );
    306                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    307
    308                if( guiInfo.isRead() && mscVal.length() != 0 ) {
    309                        final String gamenId            = guiInfo.getKey();
    310                        final UserInfo userInfo = getUser();
    311                        final Map<String,FavoriteGUIData> favoriteMap = userInfo.getFavoriteMap();
    312
    313                        // 6.3.9.0 (2015/11/06) Use one line for each declaration, it enhances code readability.(PMD)
    314                        final String fgEdit;
    315                        final String image;
    316                        final String updateLabel;
    317                        if( favoriteMap.containsKey( gamenId ) ){
    318                                fgEdit = "0";
    319                                image  = "FAV_MENU_OUT.gif";
    320                                updateLabel  = getLabel( "DELETE" );
    321                        }
    322                        else {
    323                                fgEdit = "1";
    324                                image  = "FAV_MENU_IN.gif";
    325                                updateLabel  = getLabel( "INSERT" );
    326                        }
    327
    328                        final String geContextName = HybsSystem.sys( "GE_CONTEXT_NAME" );
    329                        if( geContextName.isEmpty() ) {
    330                                final String errMsg = "システムパラメータ GE_CONTEXT_NAME が設定されていません。";
    331                                throw new HybsSystemException( errMsg );
    332                        }
    333
    334                        buf.append( "<a href=\"/").append( geContextName )
    335                                .append("/jsp/GE0014/update.jsp?fgEdit=" ).append( fgEdit )
    336                                .append( "&command=NEW&SYSTEM_ID="      ).append( userInfo.getParameter( "SYSTEM_ID" ) )
    337                                .append( "&GUIKEY="                     ).append( gamenId )
    338                                .append( "&CONTEXT_URL="        ).append( userInfo.getParameter( "CONTEXT_URL" ) )
    339                                .append( "\"><img src=\""       ).append( userInfo.getParameter( "JSP" ) )
    340                                .append( "/image/"                      ).append( image )
    341                                .append( "\" title=\""          ).append( StringUtil.htmlFilter( getLabel( "FAVORITE_MENU" ),true ) )   // 6.2.2.0 (2015/03/27)
    342                                .append( ' '                            ).append( updateLabel )
    343                                .append( "\" /></a>"            );
    344                }
    345
    346                return buf.toString();
    347        }
    348
    349        /**
    350         * 【TAG】直接アクセスできる形式のリンクを作成するかどうか[true/false]を指定します(初期値:false)。
    351         *
    352         * @og.tag
    353         * trueは、指定の画面のフレームレベルでの指定になります。false は、トップフレームを
    354         * 含む形なので、通常の登録画面と同じ形式になります。
    355         * 初期値は、false(直接リンクしない)です。
    356         *
    357         * @param       flag 作成可否 [true:する/false:しない]
    358         */
    359        public void setDirect( final String flag ) {
    360                direct = nval( getRequestParameter( flag ),direct );
    361        }
    362
    363        /**
    364         * 【TAG】リンク先の文書を表示させるフレーム、またはウィンドウの名前を指定します(初期値:_blank)。
    365         *
    366         * @og.tag リンク先のフレーム名(ターゲット属性)を設定します。
    367         *
    368         * @param       name リンク先の文書のフレーム名(ターゲット属性)
    369         */
    370        public void setTarget( final String name ) {
    371                target = nval( getRequestParameter( name ),target );
    372        }
    373
    374        /**
    375         * 【TAG】リンクを作成する時の転送先アドレスを指定します(初期値:index.jsp)。
    376         *
    377         * @og.tag
    378         * direct="false"(初期値)に使用されるリンクの転送先アドレスを指定します。
    379         * 初期値は、index.jspです。
    380         *
    381         * @param       url 転送先アドレス
    382         */
    383        public void setHref( final String url ) {
    384                href = nval( getRequestParameter( url ),href );
    385        }
    386
    387        /**
    388         * 【TAG】リンクの作成元となるメソッド[POST/GET/ALL]を指定します(初期値:GET)。
    389         *
    390         * @og.tag
    391         * ここで指定したメソッドでリクエストされた場合のみ、リンクを作成します。
    392         * 初期値は、GET です。(つまり GET のみリンクを作成します。)
    393         * これは、POST では、引数が付かない為です。(実際は付ける事ができますが・・・)
    394         * ALL は、どちらの場合でもリンクを作成しますが、先に述べたように POST では
    395         * 引数がつきません。
    396         * 初期値は、GETです。
    397         *
    398         * @param       flag リンクの作成元となるメソッド [POST/GET/ALL]
    399         */
    400        public void setMethod( final String flag ) {
    401                method = nval( getRequestParameter( flag ),method );
    402        }
    403
    404        /**
    405         * 【TAG】リンクをキャッシュするかどうか[true/false]を指定します(初期値:false)。
    406         *
    407         * @og.tag
    408         * この、favoriteLink で指定された画面を、ユーザー毎にキャッシュします。
    409         * キャッシュされた画面は、lastQuery を指定することで、取り出し(転送)
    410         * することが出来ます。
    411         * ここでのキャッシュは、direct="true" を指定した場合のアドレスです。
    412         * direct="false" は、index.jsp からのフレーム形式の為、メール等で
    413         * 送り、後ほど再開するような使い方(または、ワークフロー的な使い方)
    414         * を想定していますが、direct="true" により単独フレームデータを、
    415         * リアルタイムで使用するケース(EXCELのWebクエリーなど)で使用します。
    416         * 初期値は、falseです。
    417         *
    418         * @og.rev 3.5.5.9 (2004/06/07) リンクキャッシュより最終画面を転送表示します。
    419         *
    420         * @param       flag リンクキャッシュ [true:する/false:しない]
    421         */
    422        public void setLinkCache( final String flag ) {
    423                linkCache = nval( getRequestParameter( flag ),linkCache );
    424        }
    425
    426        /**
    427         * 【TAG】キャッシュされたリンク先に転送するかどうか[true/false]を指定します(初期値:false)。
    428         *
    429         * @og.tag
    430         * この、favoriteLink で指定された画面を、キャッシュします。
    431         * キャッシュされた画面は、lastQuery を指定することで、取り出し(転送)
    432         * することが出来ます。
    433         * ここでのキャッシュは、direct="true" を指定した場合のアドレスです。
    434         * direct="false" は、index.jsp からのフレーム形式の為、メール等で
    435         * 送り、後ほど再開するような使い方(または、ワークフロー的な使い方)
    436         * を想定していますが、direct="true" により単独フレームデータを、
    437         * リアルタイムで使用するケース(EXCELのWebクエリーなど)で使用します。
    438         * 初期値は、falseです。
    439         *
    440         * @og.rev 3.5.5.9 (2004/06/07) リンクキャッシュより最終画面を転送表示します。
    441         *
    442         * @param       flag リンク先転送 [true:する/false:しない]
    443         */
    444        public void setLastQueryRedirect( final String flag ) {
    445                redirect = nval( getRequestParameter( flag ),redirect );
    446        }
    447
    448        /**
    449         * 【TAG】お気に入りアイコンリンクを作成するかどうか[true/false]を指定します(初期値:false)。
    450         *
    451         * @og.tag
    452         * 初期値は、falseです。
    453         *
    454         * @og.rev 4.1.1.0 (2008/02/13) 新規追加。
    455         *
    456         * @param       flag お気に入りアイコンリンク作成 [true:する/false:しない]
    457         */
    458        public void setUseIcon( final String flag ) {
    459                useIcon = nval( getRequestParameter( flag ),useIcon );
    460        }
    461
    462        /**
    463         * リンクキャッシュをクリアします。
    464         * この時、poolされているオブジェクトは、ResourceManager#clear() メソッドを
    465         * 呼び出します。
    466         *
    467         * @og.rev 3.5.5.9 (2004/06/07) 新規作成
    468         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
    469         */
    470        public static void clear() {
    471                        LAST_QUERY.clear();
    472        }
    473
    474        /**
    475         * このオブジェクトの文字列表現を返します。
    476         * 基本的にデバッグ目的に使用します。
    477         *
    478         * @return このクラスの文字列表現
    479         * @og.rtnNotNull
    480         */
    481        @Override
    482        public String toString() {
    483                return ToString.title( this.getClass().getName() )
    484                                .println( "VERSION"             ,VERSION        )
    485                                .println( "direct"              ,direct         )
    486                                .println( "target"              ,target         )
    487                                .println( "method"              ,method         )
    488                                .println( "linkCache"   ,linkCache      )
    489                                .println( "redirect"    ,redirect       )
    490                                .println( "Other..."    ,getAttributes().getAttribute() )
    491                                .fixForm().toString() ;
    492        }
    493}