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.filter;
017
018import jakarta.servlet.ServletRequest;
019import jakarta.servlet.ServletResponse;
020import jakarta.servlet.http.HttpServletRequest;
021import jakarta.servlet.http.HttpServletResponse;
022import jakarta.servlet.ServletException;
023import jakarta.servlet.http.HttpFilter;
024import jakarta.servlet.FilterChain;
025import jakarta.servlet.FilterConfig;
026import jakarta.servlet.annotation.WebFilter;
027
028import jakarta.servlet.http.HttpServletResponseWrapper;
029
030import java.io.IOException;
031
032/**
033 * CacheControlFilter は、Filter インターフェースを継承した アクセス制御クラスです。
034 * web.xml で filter 設定することにより、Webアプリケーションへのアクセスを制御できます。
035 * ※ @WebFilter アノテーションだけでは、上手く動かなかった。
036 *
037 * 本来は、org.apache.catalina.filters.ExpiresFilter を使用する所だが、単純に
038 * キャッシュさせる設定だけ入れたかっただけなので、こちらにした。
039 *
040 * Cache-Control ヘッダーに対して、private,max-age=31536000,immutable を設定します。
041 * 対象は、.css , .js , .gif , .png  です。
042 * 大文字、小文字の区別有で、リクエストURIの後ろ一致で判定しています。
043 *
044 * 【WEB-INF/web.xml】
045 *     <filter>
046 *         <filter-name>CacheControlFilter</filter-name>
047 *         <filter-class>org.opengion.hayabusa.filter.CacheControlFilter</filter-class>
048 *         <init-param>
049 *             <param-name>debug</param-name>
050 *             <param-value>true</param-value>
051 *         </init-param>
052 *     </filter>
053 *
054 *     <filter-mapping>
055 *         <filter-name>CacheControlFilter</filter-name>
056 *         <url-pattern>/*;/url-pattern>
057 *     </filter-mapping>
058 *
059 * @og.group フィルター処理
060 * @og.rev 8.3.0.0 (2022/08/01) 新規追加
061 *
062 * @version  8.2
063 * @author   Kazuhiko Hasegawa
064 * @since    JDK17.0,
065 */
066@WebFilter(filterName="CacheControlFilter", urlPatterns="/*")
067public final class CacheControlFilter extends HttpFilter {                      // HttpFilter は、Servlet 4.0
068        private static final long serialVersionUID = 830020220801L ;
069
070        private boolean  isDebug        ;
071
072        /**
073         * Filter インターフェースの init メソッド (何もしません)。
074         *
075         * 実行時のURLを標準出力に出力します。
076         *
077         * @og.rev 8.3.0.0 (2022/08/01) 新規追加
078         *
079         * @param       filterConfig    FilterConfigオブジェクト
080         */
081        @Override       // Filter
082        public void init(final FilterConfig filterConfig) {
083                isDebug = Boolean.parseBoolean( filterConfig.getInitParameter("debug") );
084        }
085
086        /**
087         * フィルター処理本体のメソッドです。
088         *
089         * @og.rev 8.3.0.0 (2022/08/01) 新規追加
090         *
091         * @param       req             ServletRequestオブジェクト
092         * @param       res             ServletResponseオブジェクト
093         * @param       chain           FilterChainオブジェクト
094         * @throws IOException 入出力エラーが発生した場合、throw されます。
095         * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
096         */
097        @Override       // HttpFilter
098        public void doFilter( final ServletRequest req,
099                                                        final ServletResponse res,
100                                                        final FilterChain chain )
101                                                                throws IOException, ServletException {
102                if( req instanceof HttpServletRequest && res instanceof HttpServletResponse ) {
103                        final HttpServletRequest request = (HttpServletRequest) req;
104                        final HttpServletResponse response = (HttpServletResponse) res;
105
106                        final int type = checkType( request ) ;
107                        if( type > 0 ) {
108        //                      final CCFResponseWrapper wrapResponse = new CCFResponseWrapper( hsRes,type );
109        //                      chain.doFilter(req, wrapResponse);
110                                chain.doFilter(req, res);
111                                response.setHeader( "Cache-Control", "private,max-age=31536000,immutable" );
112                                if( type == 1 ) {
113                                        response.setCharacterEncoding( "UTF-8" );
114                                }
115                        }
116                }
117                chain.doFilter(req, res);
118        }
119
120        /**
121         * フィルターを実行するかどうか、判定します。
122         *
123         * @og.rev 8.3.0.0 (2022/08/01) 新規追加
124         *
125         * @param request ServletRequestオブジェクト
126         *
127         * @return      -1:対象外 1:テキスト 2:バイナリ
128         */
129        private int checkType( final HttpServletRequest request ) {
130                final String url = request.getRequestURI();
131
132                int rtnType = -1;
133                if( url.endsWith( ".css" ) || url.endsWith( ".js" ) ) { rtnType = 1; }
134                else if( url.endsWith( ".gif" ) || url.endsWith( ".png" )  ) { rtnType = 2; }
135
136                if( isDebug && rtnType > 0 ) { System.out.println( "CacheControlFilter=" + url ); }
137
138                return rtnType ;
139        }
140
141        /**
142         * ResponseWrapper の継承クラス
143         *
144         * とりあえず、Wrapper 無しでもヘッダーの設定が出来たので、今は未使用とします。
145         *
146         * @og.rev 8.3.0.0 (2022/08/01) 新規追加
147         */
148        final static class CCFResponseWrapper extends HttpServletResponseWrapper {
149                /** オリジナルのレスポンス */
150                protected HttpServletResponse origResponse      ;
151
152                /**
153                 * コンストラクター
154                 *
155                 * @param       response        HttpServletResponseオブジェクト
156                 * @param       type            -1:対象外 1:テキスト 2:バイナリ
157                 */
158                public CCFResponseWrapper(final HttpServletResponse response , final int type) {
159                        super(response);
160                        origResponse = response;
161                        origResponse.setHeader( "Cache-Control", "private,max-age=31536000,immutable" );
162                        if( type == 1 ) {
163                                origResponse.setCharacterEncoding( "UTF-8" );
164                        }
165        //              origResponse.setHeader( "Expires", null );
166        //              origResponse.setHeader( "Pragma" , null );
167                }
168        }
169}