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