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.servlet;
017
018// import java.io.FileInputStream;                                                                      // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidFileStream 対応
019import java.io.BufferedInputStream;                                                                     // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidFileStream 対応
020import java.io.InputStream;
021import java.io.IOException;
022import java.io.PrintWriter;
023import java.io.UnsupportedEncodingException;
024import java.util.Enumeration;
025import java.util.HashMap;
026import java.util.Map;                                                                                           // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling
027import java.util.regex.Pattern;                                                                         // 7.2.9.4 (2020/11/20)
028import java.util.regex.Matcher;                                                                         // 7.2.9.4 (2020/11/20)
029
030import java.nio.file.Paths;                                                                                     // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidFileStream 対応
031import java.nio.file.Files;                                                                                     // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidFileStream 対応
032
033import jakarta.servlet.ServletException;
034import jakarta.servlet.ServletConfig;                                                           // 7.2.9.4 (2020/11/20)
035import jakarta.servlet.ServletOutputStream;
036import jakarta.servlet.http.HttpServlet;
037import jakarta.servlet.http.HttpServletRequest;
038import jakarta.servlet.http.HttpServletResponse;
039// import jakarta.servlet.annotation.WebInitParam;                                      // 7.3.0.0 (2021/01/06)
040// import jakarta.servlet.annotation.WebServlet;                                        // 7.3.0.0 (2021/01/06)
041
042import org.opengion.fukurou.system.Closer;
043import org.opengion.hayabusa.common.HybsSystem;
044import org.opengion.hayabusa.common.HybsSystemException;
045import org.opengion.hayabusa.remote.RemoteControllable;
046
047/**
048 * 外部からキーと値を投げて処理をさせるサーブレットです。
049 * Post,Get両方に対応しています。
050 * classキーが必須です。(値はhayabusa/remote/内のクラス名)
051 *
052 * @og.rev 4.1.0.0 (2007/12/20) 新規作成
053 * @version  4.1
054 * @author   Masakazu Takahashi
055 * @since    JDK6.0,
056 *
057 */
058/*
059@WebServlet(
060        urlPatterns = "/servlet/remoteControl" ,
061        initParams  = {
062                @WebInitParam(name="filePattern", value=".*opengionV8.*|c:[/\\]temp[/\\].*")
063        }
064)
065*/
066public class RemoteControlServlet extends HttpServlet {
067        private static final long serialVersionUID      = 542020111201L ;
068        private static final String REMOTE_PKG          = "org.opengion.hayabusa.remote.";
069
070        /** 処理対象のファイルパターン(正規表現) */
071        private Pattern filePattern ;                   // 7.2.9.4 (2020/11/20) ファイルアクセスの制約(指定がない場合は、処理しない)。
072
073        /**
074         * デフォルトコンストラクター
075         *
076         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
077         */
078        public RemoteControlServlet() { super(); }              // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
079
080        /**
081         * Servlet の 初期値設定を行います。
082         *
083         * WEB-INF/web.xml ファイルで、<servlet> タグ内で初期値設定を行います。
084         * <init-param>
085         *     <param-name>filePattern</param-name>
086         *     <param-value>c:/opengionV8|c:/temp</param-value>
087         * </init-param>
088         *
089         * @og.rev 7.2.9.4 (2020/11/20) ファイルアクセスの制約(指定がない場合は、処理しない)。
090         *
091         * @param       config  ServletConfigオブジェクト
092         */
093        @Override
094        public void init( final ServletConfig config ) throws ServletException {
095                super.init( config );
096
097                final String filePtn = config.getInitParameter("filePattern");
098                if( filePtn != null && !filePtn.isEmpty() ) {
099                        filePattern = Pattern.compile( filePtn );
100                }
101        }
102
103        /**
104         * Getメソッドで与えられたrequestをcallClassメソッドに渡します。
105         * callClassメソッドではclassパラメータの値を利用してクラスをロードし、処理を行います。
106         * 具体的な処理はcallClassメソッドをご覧下さい。
107         *
108         * @param request HttpServletRequestリクエスト
109         * @param response HttpServletResponseレスポンス
110         * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
111         * @throws IOException 入出力エラーが発生したとき
112         */
113        @Override
114        public void doGet( final HttpServletRequest request, final HttpServletResponse response )       throws ServletException, IOException {
115                callClass( request, response );
116        }
117
118        /**
119         * Postメソッドで与えられたrequestをcallClassメソッドに渡します。
120         * callClassメソッドではclassパラメータの値を利用してクラスをロードし、処理を行います。
121         * 具体的な処理はcallClassメソッドをご覧下さい。
122         *
123         * @param request HttpServletRequestリクエスト
124         * @param response HttpServletResponseレスポンス
125         * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
126         * @throws IOException 入出力エラーが発生したとき
127         */
128        @Override
129        public void doPost( final HttpServletRequest request, final HttpServletResponse response )      throws ServletException, IOException {
130                callClass( request, response );
131        }
132
133        /**
134         * POSTとGETに対する実際の処理です
135         * 必須パラメータclassで与えられたクラス名でorg.opengion.hayabusa.remoteから
136         * クラスをロードし、MAPに格納したrequestパラメータをそのクラスに対して渡します。
137         * ロードするクラスはRemoteControllableを実装している必要があります。
138         * ロードしたクラスの処理が終了すると、返されたStringをresponseに出力して終了します。
139         * なお、classパラメータがnullの場合は何もせずに終了します。
140         *
141         * @og.rev 5.4.2.0 (2011/12/01) フォワード対応
142         * @og.rev 7.2.9.4 (2020/11/20) ファイルアクセスの制約(指定がない場合は、処理しない)。
143         *
144         * @param request リクエスト
145         * @param response レスポンス
146         * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
147         * @throws IOException 入出力エラーが発生したとき
148         */
149        private void callClass( final HttpServletRequest request, final HttpServletResponse response ) throws ServletException, IOException {
150                // 5.4.2.0 (2011/12/01) リクエストのエンコードを指定
151                try {
152                        request.setCharacterEncoding( "UTF-8" );
153                }
154                catch( final UnsupportedEncodingException ex ) {
155                        throw new HybsSystemException( ex );
156                }
157
158                // 5.4.2.0 (2011/12/01) フォワード対応
159                // 7.2.9.4 (2020/11/20) ファイルアクセスの制約(指定がない場合は、処理しない)。
160                final String file = request.getParameter( "file" );
161//              if( file != null && file.length() > 0 ) {
162                if( file != null && !file.isEmpty() && filePattern != null ) {                  // 7.2.9.4 (2020/11/20)
163                        final Matcher match = filePattern.matcher( file );                                      // 7.2.9.4 (2020/11/20)
164                        if( match.matches() ) {                                                                                         // 7.2.9.4 (2020/11/20)
165                                response.setContentType( "application/octet-stream" );
166                                // ファイル内容の出力
167//                              FileInputStream fin = null;
168                                InputStream fin = null;
169                                ServletOutputStream out = null;
170                                try {
171                                        // 対応済み:spotbugs:サーブレットの絶対パストラバーサル
172                                        // 8.5.4.2 (2024/01/12) PMD 7.0.0 AvoidFileStream 対応
173//                                      fin = new FileInputStream( file );
174                                        fin = new BufferedInputStream( Files.newInputStream(Paths.get(file)) );
175                                        out = response.getOutputStream();
176
177                                        // ファイル読み込み用バッファ
178                                        final byte buffer[]  = new byte[4096];
179                                        int size;
180                                        while((size = fin.read(buffer))!=-1) {
181                                                out.write(buffer,0, size);
182                                                out.flush();
183                                        }
184                                }
185                                finally {
186                                        Closer.ioClose( fin );
187                                        Closer.ioClose( out );
188                                }
189                        }
190                }
191                else {
192                        final String clazz = request.getParameter( "class" ); // パラメータ"class"だけは必ず必要
193
194                        if( clazz == null ) {
195                                return; // 暫定処理
196                        }
197
198                        final Enumeration<?> paramEnm = request.getParameterNames();            // 4.3.3.6 (2008/11/15) Generics警告対応
199//                      final HashMap<String,String> paramMap = new HashMap<>();
200                        final Map<String,String> paramMap = new HashMap<>();                            // 8.5.4.2 (2024/01/12) PMD 7.0.0 LooseCoupling
201                        while( paramEnm.hasMoreElements() ) {
202                                final String key = (String)paramEnm.nextElement();
203                                paramMap.put( key, request.getParameter( key ) );
204                        }
205
206                        final RemoteControllable rmtC = HybsSystem.newInstance( REMOTE_PKG + clazz );
207                        final String rtnString = rmtC.remoteControl( paramMap );
208                        response.setContentType( "text/xml; charset=UTF-8" );
209                        final PrintWriter out = response.getWriter();
210                        out.println( rtnString );
211                        out.flush();
212                        out.close();
213                }
214        }
215}