/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.servlet;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.opengion.fukurou.system.Closer;
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.remote.RemoteControllable;

/**
 * 外部からキーと値を投げて処理をさせるサーブレットです。
 * Post,Get両方に対応しています。
 * classキーが必須です。(値はhayabusa/remote/内のクラス名)
 *
 * @og.rev 4.1.0.0 (2007/12/20) 新規作成
 * @version  4.1
 * @author   Masakazu Takahashi
 * @since    JDK6.0,
 *
 */
public class RemoteControlServlet extends HttpServlet {
	private static final long serialVersionUID	= 542020111201L ;
	private static final String REMOTE_PKG		= "org.opengion.hayabusa.remote.";

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
	 */
	public RemoteControlServlet() { super(); }		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * Postメソッドで与えられたrequestをcallClassメソッドに渡します。
	 * callClassメソッドではclassパラメータの値を利用してクラスをロードし、処理を行います。
	 * 具体的な処理はcallClassメソッドをご覧下さい。
	 *
	 * @param request HttpServletRequestリクエスト
	 * @param response HttpServletResponseレスポンス
	 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
	 * @throws IOException 入出力エラーが発生したとき
	 */
	@Override
	public void doPost( final HttpServletRequest request, final HttpServletResponse response )	throws ServletException, IOException {
		callClass( request, response );
	}

	/**
	 * Getメソッドで与えられたrequestをcallClassメソッドに渡します。
	 * callClassメソッドではclassパラメータの値を利用してクラスをロードし、処理を行います。
	 * 具体的な処理はcallClassメソッドをご覧下さい。
	 *
	 * @param request HttpServletRequestリクエスト
	 * @param response HttpServletResponseレスポンス
	 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
	 * @throws IOException 入出力エラーが発生したとき
	 */
	@Override
	public void doGet( final HttpServletRequest request, final HttpServletResponse response )	throws ServletException, IOException {
		callClass( request, response );
	}

	/**
	 * POSTとGETに対する実際の処理です
	 * 必須パラメータclassで与えられたクラス名でorg.opengion.hayabusa.remoteから
	 * クラスをロードし、MAPに格納したrequestパラメータをそのクラスに対して渡します。
	 * ロードするクラスはRemoteControllableを実装している必要があります。
	 * ロードしたクラスの処理が終了すると、返されたStringをresponseに出力して終了します。
	 * なお、classパラメータがnullの場合は何もせずに終了します。
	 *
	 * @og.rev 5.4.2.0 (2011/12/01) フォワード対応
	 *
	 * @param request リクエスト
	 * @param response レスポンス
	 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
	 * @throws IOException 入出力エラーが発生したとき
	 */
	private void callClass( final HttpServletRequest request, final HttpServletResponse response ) throws ServletException, IOException {
		// 5.4.2.0 (2011/12/01) リクエストのエンコードを指定
		try {
			request.setCharacterEncoding( "UTF-8" );
		}
		catch( final UnsupportedEncodingException ex ) {
			throw new HybsSystemException( ex );
		}

		// 5.4.2.0 (2011/12/01) フォワード対応
		final String file = request.getParameter( "file" );
		if( file != null && file.length() > 0 ) {
			response.setContentType( "application/octet-stream" );
			// ファイル内容の出力
			FileInputStream     fin = null;
			ServletOutputStream out = null;
			try {
				fin = new FileInputStream( file );
				out = response.getOutputStream();

				// ファイル読み込み用バッファ
				final byte buffer[]  = new byte[4096];
				int size;
				while((size = fin.read(buffer))!=-1) {
					out.write(buffer,0, size);
					out.flush();
				}
			}
			finally {
				Closer.ioClose( fin );
				Closer.ioClose( out );
			}
		}
		else {
			final String clazz = request.getParameter( "class" ); // パラメータ"class"だけは必ず必要
			if( clazz == null ) {
				return; // 暫定処理
			}

			final Enumeration<?> paramEnm = request.getParameterNames();		// 4.3.3.6 (2008/11/15) Generics警告対応
			final HashMap<String,String> paramMap = new HashMap<>();
			while( paramEnm.hasMoreElements() ) {
				final String key = ( String )( paramEnm.nextElement() );
				paramMap.put( key, request.getParameter( key ) );
			}

			final RemoteControllable rmtC = HybsSystem.newInstance( REMOTE_PKG + clazz );
			final String rtnString = rmtC.remoteControl( paramMap );
			response.setContentType( "text/xml; charset=UTF-8" );
			final PrintWriter out = response.getWriter();
			out.println( rtnString );
			out.flush();
			out.close();
		}
	}
}
