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