/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   ソースファイル名：JCCcomFTPClientUtil.java
*   作成者          ：富士通
*   日付            ：2011/05/23
*＜機能概要＞
*   FTPサーバへ接続し、ファイル転送を実行する
*＜修正履歴＞
*   バージョン  修正日      修正者      修正内容
*   v1.0版      2011/05/23  富士通      新規作成
*   v5.00.00    2013/10/25  FJ          【OM-2013-0001476】
*   v5.00.01    2014/01/14  FJ          ackファイル上書きチェック
*   v7.00.00    2014/03/17  FJ          ログ出力追加
*  v10.00.00    2014/09/03  FJ          OM-2014-0002865 調査用ログ追加
*  v22.00.00    2016/01/20  FJ)大山     OM-2015-0001555  
**********************************************************************/
package eo.common.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;

import com.fujitsu.futurity.common.JCMLogCommon;
import com.fujitsu.futurity.common.JCMsvlLogOutputCommon;
import com.fujitsu.futurity.common.JSYLogBase;
import com.fujitsu.futurity.model.common.JCMAPLConstMgr;

public class JCCFtpClientUtil {

	private Socket ctrlSocket = null;;
	private PrintWriter ctrlOutput= null;;
	private BufferedReader ctrlInput = null;;
	private byte[] localHostAddress = null;
	
	private String host = null;
	private String	port= null;
	private String	user= null;
	private String	password= null;
	private int	retryInterval= 0;
	private int	retryCountUni= 0;
	private int	retryCountGen= 0;
	private String transferMode = null;
	private String hostDirectory = null;
	private String[] fileList = null;
	private HashMap<String, Object> msgList = null;
	
	// 2012/05/22 現在日時をyyyyMMddHHmmssSSS形式で保持する start
	private String nowDtm = null;
	// 2012/05/22 現在日時をyyyyMMddHHmmssSSS形式で保持する end
	
// 2012/08/06 FST)arata あて先がwindowsサーバーかどうかを判別するフラグ start
	boolean windowsSvFlg = false;
	private static final String WINDOWS_LINE_SEPARATOR = "\r\n";
// 2012/08/06 FST)arata あて先がwindowsサーバーかどうかを判別するフラグ end
	
	//@処理結果詳細Map
	private static final String ERR_KBN = "ERR_KBN";
	private static final String CONNECT_ERR = "CONNECT_ERR";
	private static final String FILE_ERR = "FILE_ERR";
	
	//A接続エラー詳細Map
	private static final String ERR_FLG = "ERR_FLG";
	private static final String ERR_MESSAGE = "ERR_MESSAGE";
	private static final String ERR_CD = "ERR_CD";
	
	//Bファイルエラー詳細Map（処理がエラー等で中断した場合は、処理を行ったファイルまでリスト化される。
	private static  String FILE_NAME = "FILE_NAME";
	
	//一時作業用フォルダパス（毎回の処理の保存用）
	private ArrayList<String> tmpFolderPath = new ArrayList<String>();
	//一時作業用フォルダパス（全てのループの保存用）
	private ArrayList<String> tmpFolderPathStore = new ArrayList<String>();
	
	// 受信コード
	private static final String READY = "220";
	private static final String USER = "331";
	private static final String PASS = "230";
	private static final String COMMAND = "200";
	private static final String OPEN = "150";
	private static final String TRANSFER = "226";
	private static final String CWD = "250";
	private static final String PASV = "227";
	private static final String QUIT = "221";
	private static final String DELE = "250";
	private static final String[] RECEIVECODE = {"COMMAND", "DELE"};

	// 転送モード
	private static final HashMap<String, String> TranMode = new HashMap<String, String>();
	static{
		TranMode.put("A","A");
		TranMode.put("B","I");
	};
	
	// エラー判定文字列
	private static final String ERROR = "ERROR";
	
	private static final Object TRUE = true;
	
	private static final String EXTEND_ACK = "ack";
	
	// リトライ時の次回処理制御用
	private static final int NEXTPROC_END = 0;
	private static final int NEXTPROC_UPLOAD = 1;
	private static final int NEXTPROC_SIZECHECK = 2;
	private static final int NEXTPROC_FILECREATE = 4;
	
	// アップロード時のファイル存在有無チェック判定フラグ 2012/01/04
	private boolean fileExistFlg = false;
	
	// 2012/11/28 FST_mukuo)ファイルサイズチェックエラー時に上書き禁止エラーを抑制する start
	private boolean fileExistIgnoreFlg = false;
	// 2012/11/28 FST_mukuo)ファイルサイズチェックエラー時に上書き禁止エラーを抑制する end
	
	/**
	 * コンストラクタ
	 */
	public JCCFtpClientUtil() {
	}
	
	/**
	 * FTPクライアントのPUT処理です。<br>
	 * FTPクライアントのPUTを行います。<br>
	 * 
	 * @param host ホスト名
	 * @param port ポート番号
	 * @param user ユーザID
	 * @param password パスワード
	 * @param retryInterval リトライ間隔
	 * @param retryCountUni リトライ回数(個別)
	 * @param retryCountGen リトライ回数(全体)
	 * @param transferMode 転送モード
	 * @param hostDirectory 転送先ディレクトリ
	 * @param fileList 転送ファイルリスト
	 * @param interFaceId インターフェースID
	 * @param msgList 処理結果詳細を格納したHashMap。内容は下記@参照 <BR>
	 * <pre>
	 *  @処理結果詳細HashMap
	 *   ERR_KBN       (Integer)  エラー区分。0:エラーなし 1:接続エラー 2:ファイルエラー
	 *   CONNECT_ERR   (HashMap)  接続エラー。内容は下記A参照
	 *   FILE_ERR      (ArrayList<Hash Map>)  ファイルエラー。内容は下記B参照
     * </pre>
	 * <pre>
	 *  A接続エラー詳細HashMap
	 *   ERR_FLG       (Boolean) 成功:true 失敗:false
	 *   ERR_MESSAGE   (String)  エラーメッセージ
	 *   ERR_CD        (String)  エラーコード。詳細は下記C参照
     * </pre>
 	 * <pre>
	 *  Bファイルエラー詳細HashMap
	 *   FILE_NAME     (String)  ファイル名
	 *   ERR_FLG       (Boolean) 成功:true 失敗:false
	 *   ERR_MESSAGE   (String)  エラーメッセージ
	 *   ERR_CD        (String)  エラーコード。詳細は下記C参照
     * </pre>
 	 * <pre>
	 *  Cエラーコード一覧
	 *   200 ソケット接続に失敗
	 *   201 ユーザー認証に失敗
	 *   201 パスワード認証に失敗
	 *   202 リモートホストの指定したディレクトリ移動に失敗
	 *   203 一時作業用フォルダ作成に失敗
	 *   203 ダウンロードファイルオープンに失敗
	 *   203 ダウンロードファイル転送に失敗
	 *   204 アップロードファイルオープンに失敗
	 *   204 アップロードファイル転送に失敗
	 *   205 ファイル削除に失敗
	 *   206 切断に失敗
	 *   207 CDコマンドの実行に失敗（ファイルアップロード時）
	 *   208 CDコマンドの実行に失敗（ファイルダウンロード時）
	 *   209 CDコマンドの実行に失敗（サーバからの削除時）
	 *   210 転送モードの設定に失敗（ファイルアップロード時）
	 *   211 転送モードの設定に失敗（ファイルダウンロード時）
	 *   212 監視完了ファイルの生成に失敗
	 *   300 ダウンロードファイルの書き込みに失敗
	 *   302 ファイルバックアップに失敗
	 *   303 ファイルサイズ不一致
	 *   304 その他の例外が発生
	 *   305 ファイルが存在しない（監視完了ファイル作成時）
	 *   306 ファイルが存在しない（バックアップファイル作成時）
	 *   307 ファイルが存在しない（ダウンロード時）
	 *   308 ファイルが存在しない（アップロード時）
	 *   310 ファイルが存在しない（サイズチェック時）
     * </pre>
	 * @return 処理結果（正常：true／エラー：false） 
	 * @exception JCCFrameworkExceptionがスローされます。
	 */
	public boolean putFtp(String host, String port, String user, String password,
			int retryInterval,int retryCountUni, int retryCountGen, String transferMode, String hostDirectory,
			String[] fileList, String interFaceId, HashMap<String, Object> msgList)
	{
		return putFtpBase
		(
			host, 
			port, 
			user, 
			password, 
			retryInterval, 
			retryCountUni,
			retryCountGen,
			transferMode,
			hostDirectory,
			fileList,
			interFaceId,
			false,
			msgList
		);
	}

	/**
	 * FTPクライアントのPUT処理です。<br>
	 * FTPクライアントのPUTを行います。<br>
	 * 
	 * @param host ホスト名
	 * @param port ポート番号
	 * @param user ユーザID
	 * @param password パスワード
	 * @param retryInterval リトライ間隔
	 * @param retryCountUni リトライ回数(個別)
	 * @param retryCountGen リトライ回数(全体)
	 * @param transferMode 転送モード
	 * @param hostDirectory 転送先ディレクトリ
	 * @param fileList 転送ファイルリスト
	 * @param interFaceId インターフェースID
	 * @param transOnlyMode 
	 * 　　　　(true:ackファイル及びバックアップファイルを生成しない／false:ackファイルとバックアップファイルを生成する)
	 * @param msgList 処理結果詳細を格納したHashMap。
	 * </pre>
	 * @return 処理結果（正常：true／エラー：false） 
	 * @exception JCCFrameworkExceptionがスローされます。
	 */
	public boolean putFtp(String host, String port, String user, String password,
			int retryInterval,int retryCountUni, int retryCountGen, String transferMode, String hostDirectory,
			String[] fileList, String interFaceId, boolean transOnlyMode, HashMap<String, Object> msgList)
	{
		return putFtpBase
		(
			host, 
			port, 
			user, 
			password, 
			retryInterval, 
			retryCountUni,
			retryCountGen,
			transferMode,
			hostDirectory,
			fileList,
			interFaceId,
			transOnlyMode,
			msgList
		);
	}
	
	/**
	 * FTPクライアントのPUT処理です。<br>
	 * FTPクライアントのPUTを行います。<br>
	 * 
	 * @param host ホスト名
	 * @param port ポート番号
	 * @param user ユーザID
	 * @param password パスワード
	 * @param retryInterval リトライ間隔
	 * @param retryCountUni リトライ回数(個別)
	 * @param retryCountGen リトライ回数(全体)
	 * @param transferMode 転送モード
	 * @param hostDirectory 転送先ディレクトリ
	 * @param fileList 転送ファイルリスト
	 * @param interFaceId インターフェースID
	 * @param transOnlyMode 
	 * 　　　　(true:ackファイル及びバックアップファイルを生成しない／false:ackファイルとバックアップファイルを生成する)
	 * @param msgList 処理結果詳細を格納したHashMap。
	 * </pre>
	 * @return 処理結果（正常：true／エラー：false） 
	 * @exception JCCFrameworkExceptionがスローされます。
	 */
	private boolean putFtpBase(String host, String port, String user, String password,
			int retryInterval,int retryCountUni, int retryCountGen, String transferMode, String hostDirectory,
			String[] fileList, String interFaceId, boolean transOnlyMode, HashMap<String, Object> msgList)
	{
		// 2012/05/22 現在時刻を取得してクラス内で保持する start
		Date date = new Date();
		SimpleDateFormat dFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		this.nowDtm = dFormat.format(date);
		// 2012/05/22 現在時刻を取得してクラス内で保持する end

		// 2013/10/25 ERR_KBN 初期値設定
		msgList.put(ERR_KBN, new Integer(0));

		// パラメータチェック
		// ホスト名チェック	
		// ホスト名がnull、または空白の場合
		if(null == host || "".equals(host))
		{
			throw new JCCFrameworkException("ホスト名がnullもしくは空白です");
		}
		
		// ポート番号チェック	
		// ポート番号がnull、または空白の場合
		
		if(null == port || "".equals(port))
		{
			throw new JCCFrameworkException("ポート番号がnullもしくは空白です");
		}
		
		// ユーザー名チェック	
		// ユーザ名がnull、または空白の場合
		
		if(null == user || "".equals(user))
		{
			throw new JCCFrameworkException("ユーザ名がnullもしくは空白です");
		}
		
		// パスワードチェック	
		// パスワードがnull、または空白の場合
		if(null == password || "".equals(password))
		{
			throw new JCCFrameworkException("パスワードがnullもしくは空白です");
		}
		
		// リトライ間隔	
		// リトライ間隔が1以下の場合
		if(1 > retryInterval)
		{
			throw new JCCFrameworkException("リトライ間隔の値が不正です");
		}
		
		// 連続リトライ回数	
		// 連続リトライ回数が0または-2以下の場合
		if(0 >= retryCountUni)
		{
			throw new JCCFrameworkException("連続リトライ回数の値が不正です");
		}
		
		// 総リトライ回数	
		// 総リトライ回数が0の場合
		if(0 == retryCountGen || -2 >= retryCountGen)
		{
			throw new JCCFrameworkException("総リトライ回数の値が不正です");
		}
		
		// 転送モードチェック	
		// 転送モードが"A"(:Ascii)、"B"(Binary)以外の場合
		if(!this.TranMode.containsKey(transferMode))
		{
			throw new JCCFrameworkException("転送モードが不正です");
		}
		
		//(h) ホストディレクトリパスチェック
		//ホストディレクトリパスがnull、または空白の場合
		if(null == hostDirectory|| "".equals(hostDirectory))
		{
			throw new JCCFrameworkException("ホストディレクトリパスがnullもしくは空白です");
		}
		
		// ファイルリストチェック	
		// ファイルリストがnull、または要素数が０の場合
		if(null == fileList || 0 == fileList.length )
		{
			throw new JCCFrameworkException("ファイルリストがnullもしくは要素数０です");
		}
		
		// ファイルリストチェック	
		// ファイルリストにnullの要素が含まれている場合
		for(int i=0; i<fileList.length; i++){
			if(null == fileList[i] || fileList[i].isEmpty()){
				throw new JCCFrameworkException("ファイルリストにnullの要素が含まれています。");
			}
		}
		
		// インターフェイスIDチェック	
		// インターフェイスIDがnull、または空白の場合
		if(null == interFaceId || "".equals(interFaceId))
		{
			throw new JCCFrameworkException("インターフェイスIDがnullもしくは空白です");
		}
		
// 2012/08/06 FST)arata ホスト名に改行（\r\n）が挿入されている場合は、FAXサーバー（windowsサーバー）とみなし、windowsサーバー用の分岐を通過させる start
		if(host.indexOf(WINDOWS_LINE_SEPARATOR) != -1)
		{
			windowsSvFlg = true;
			host = host.substring(0, host.indexOf(WINDOWS_LINE_SEPARATOR));
		}
		else
		{
			windowsSvFlg = false;
		}
// 2012/08/06 FST)arata ホスト名に改行（\r\n）が挿入されている場合は、FAXサーバー（windowsサーバー）とみなし、windowsサーバー用の分岐を通過させる start
		
		// パラメータ値保持
		// 引数として取得した値をフィールドにコピーする。
		
		this.host = host;
		this.port = port;
		this.user = user;
		this.password = password;
		this.retryInterval = retryInterval;
		this.retryCountUni = retryCountUni;
		this.retryCountGen = retryCountGen;
		this.transferMode = transferMode;
		this.hostDirectory = hostDirectory;
		this.msgList = msgList;
		
		// 転送モード書き換え
		this.transferMode = this.TranMode.get(this.transferMode);
		
		
		// ファイル存在有無確認用フラグの初期化  2012/01/04
		this.fileExistFlg = false;
		
		//(3) FTP転送処理
		//@リトライ処理に必要な変数、リトライ回数、スリープ回数を0で初期化する。
		int retryCountUniWork = 0;	// 総リトライ回数
		int retryCountGenWork = 0;	// 連続リトライ回数
		boolean returnCode = false;
		String filePathWk = "";
		int nextProc = 0;	// リトライ時の次回処理区分
		boolean conFlg = false;	// コネクション接続確認用
		String[] fileListSave = fileList;	// バックアップ時に使用するファイルリスト
		
		// 2012/11/28 FST_mukuo)上書き禁止モードをプロパティ制御に変更 start
		String overWriteMode = JCMAPLConstMgr.getString("FTP_OVERWRITE_MODE");
		// 2012/11/28 FST_mukuo)上書き禁止モードをプロパティ制御に変更 start
		
		// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
		printLog(msgList, "ホスト名：" + this.host);
		printLog(msgList, "ポート番号：" + this.port);
		printLog(msgList, "ユーザーID：" + this.user);
		printLog(msgList, "リトライ間隔（秒）：" + this.retryInterval);
		printLog(msgList, "リトライ回数（単体）：" + this.retryCountUni);
		printLog(msgList, "リトライ回数（全体）：" + this.retryCountGen);
		printLog(msgList, "転送モード：" + this.transferMode + "(" + transferMode + ")");
		printLog(msgList, "転送先ディレクトリ：" + this.hostDirectory);
		printLog(msgList, "上書きモード：" + overWriteMode);
		// 2013/01/30 FTP接続情報ログ出力 end
		
		//ファイル数分繰り返し
		for (int fileCount = 0; fileCount < fileList.length; fileCount++)
		{
			// 2012/11/28 FST_mukuo)上書き禁止モードをプロパティ制御に変更 start
			if(null != overWriteMode && "1".equals(overWriteMode))
			{
				this.fileExistIgnoreFlg = true;
			}
			else
			{
				this.fileExistIgnoreFlg = false;
			}
			// 2012/11/28 FST_mukuo)上書き禁止モードをプロパティ制御に変更 end
			
			this.fileList = new String[1];
			this.fileList[0] = fileList[fileCount];
			
			returnCode = false;
			// 接続処理から開始
			nextProc = NEXTPROC_UPLOAD;
			
			//リトライ処理
			while (NEXTPROC_END < nextProc)	
			{
				// 連続リトライ回数 >= this.retryCountUniの場合
				if(retryCountUniWork >= this.retryCountUni)
				{
					// 無限リトライ時以外
					if (-1 != this.retryCountGen){
						// 総リトライ回数インクリメント
						retryCountGenWork++;
						// 連続リトライ回数 >= this.retryCountUniの場合
						if(retryCountGenWork >= this.retryCountGen)
						{
							// ソケット接続に成功している場合
							if(conFlg){
								delete(msgList);
							}
							// 規定回数到達のためBREAK
							break;
						}
					}
					try
					{
						// リトライ間隔分スリープ
						Thread.sleep(retryInterval * 1000);
						retryCountUniWork = 0;
					}
					catch (InterruptedException e)
					{
						try{
							// 終了処理
							finallyProc();
							// 待機変数クリア
							paramClear();
						}catch(JCCFrameworkException ex){
							
						}
						throw new JCCFrameworkException("リトライ間に実施したスリープ処理でエラーが発生しました。", e);
					}
				}
				if (this.fileList[0].equals(filePathWk))
				{
					retryCountUniWork++;
				}
				filePathWk = this.fileList[0];
				
				// 処理対象のファイル情報をHashMapから削除
				// データが存在しない場合（初回）はFALSEが返るが無視
				fileInfoClear(this.fileList[0]);
				
				// コネクションフラグをOFF
				conFlg = false;
				
				// コネクションが切断されていた場合
				if(null != ctrlSocket && null != ctrlOutput && null != ctrlInput){
					try
					{
						// 実コネクションが切れていないか確認
						if(0 == cd(this.hostDirectory)){
							conFlg = true;
						}
					}
					catch(JCCFrameworkException e)
					{
						// IPアドレスが誤っている場合にもExceptionが出るため、
						// リトライを繰り返してエラー終了させる。
					}
				}
				
				if(!conFlg){
					// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
					printLog(msgList, "connection start");
					// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end

					// FTP接続処理を行う
					returnCode = ftpConnection(msgList);
					if(!returnCode)
					{
						conFlg = false;
						continue;
					}
					
					// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
					printLog(msgList, "connection end");
					// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
				}
				
				// リトライ時次回処理区分で振り分け
				switch(nextProc){
					case NEXTPROC_UPLOAD:
						// FTPアップロード処理を行い、フィールドに
						// 保持しているファイルをESBサーバに送信
						// 2011/11/15 ackファイルをディレクトリに転送する対応 FST start
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
						printLog(msgList, "upload start(ファイル名：" + this.fileList[0] + ")");
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
						returnCode = upload(msgList, false);
						// 2011/11/15 ackファイルをディレクトリに転送する対応 FST end
						// ファイルの存在チェックフラグを確認する 2012/01/04 start
						if(this.fileExistFlg == true)
						{
							// 終了処理後に例外をスローする
							finallyProc();
							paramClear();
							throw new JCCFrameworkException("既に同名のファイルが指定のディレクトリに存在しています。" + fileList[fileCount]);
						}
						// ファイルの存在チェックフラグを確認する 2012/01/04 end
						if(!returnCode)
						{
							// 2012/11/28 FST_mukuo)アップロードリトライ時に上書き禁止エラーを抑制する start
							this.fileExistIgnoreFlg = true;
							// 2012/11/28 FST_mukuo)アップロードリトライ時に上書き禁止エラーを抑制する end
							
							// アップロードを再試行するよう制御
							nextProc = NEXTPROC_UPLOAD;
							continue;
						}
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
						printLog(msgList, "upload end");
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
					case NEXTPROC_SIZECHECK:
						// ファイルサイズチェック送信した
						// ファイルとローカルのファイルサイズチェック
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
						printLog(msgList, "file size check start(ファイル名：" + this.fileList[0] + ")");
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
						returnCode = fileSizeCheck(msgList);
						if(!returnCode)
						{
							// 2012/11/28 FST_mukuo)ファイルサイズチェックエラー時に上書き禁止エラーを抑制する start
							this.fileExistIgnoreFlg = true;
							// 2012/11/28 FST_mukuo)ファイルサイズチェックエラー時に上書き禁止エラーを抑制する start
							
							// アップロードから再試行するよう制御
							nextProc = NEXTPROC_UPLOAD;
							continue;
						}
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
						printLog(msgList, "file size check end");
						// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
						break;
					default:
						try{
							// 終了処理
							finallyProc();
							// 待機変数クリア
							paramClear();
						}catch(JCCFrameworkException ex){
						}
						throw new JCCFrameworkException("FTP転送処理中に不明な内部コードが検出されました。");
				}
				// 処理終了を設定
				nextProc = NEXTPROC_END;
			}
			
			// エラーの場合はリトライ回数を
			// 使い果たしているため処理終了
			if(!returnCode){
				break;
			}
		}
		
		if(transOnlyMode == false)
		{
			if(returnCode){
				// リトライ開始時にカウントをインクリメント
				// するため、成功した分をデクリメント
				// リトライ判定後、連続リトライカウントを戻すため
				// filePathWkへ1件目のackファイルを設定
				if (this.fileList[0].equals(filePathWk))
				{
					retryCountUniWork = 0;
				}
				
				filePathWk = "";
				
				//ファイル数分繰り返し
				for(int i = 0; i < fileList.length; i++)
				{
					this.fileList = new String[1];
					// 待機変数のファイルリストに処理対象のファイルパスを設定
					this.fileList[0] = chgExtention(fileList[i], EXTEND_ACK);
					
					// ackファイル作成から開始
					nextProc = NEXTPROC_FILECREATE;
					
					//リトライ処理
					while (NEXTPROC_END < nextProc)	
					{
						if (this.fileList[0].equals(filePathWk))
						{
							retryCountUniWork++;
						}
						
						// 連続リトライ回数 >= this.retryCountUniの場合
						if(retryCountUniWork >= this.retryCountUni)
						{
							// 無限リトライ時以外
							if (-1 != this.retryCountGen){
								// 総リトライ回数インクリメント
								retryCountGenWork++;
								// 連続リトライ回数 >= this.retryCountUniの場合
								if(retryCountGenWork >= this.retryCountGen)
								{
									delete(msgList);
									// 規定回数到達のためBREAK
									break;
								}
							}
							try
							{
								// リトライ間隔分スリープ
								Thread.sleep(retryInterval * 1000);
								retryCountUniWork = 0;
							}
							catch (InterruptedException e)
							{
								try{
									// 終了処理
									finallyProc();
									// 待機変数クリア
									paramClear();
								}catch(JCCFrameworkException ex){
									
								}
								throw new JCCFrameworkException("リトライ間に実施したスリープ処理でエラーが発生しました。", e);
							}
						}
						
						filePathWk = this.fileList[0];
						
						// 処理対象のファイル情報をHashMapから削除
						// データが存在しない場合（初回）はFALSEが返るが無視
						fileInfoClear(this.fileList[0]);
						
						// リトライ時次回処理区分で振り分け
						switch(nextProc){
							case NEXTPROC_FILECREATE:
								// ローカルにackファイルを作成
								returnCode = createAckFile(msgList);
								if(!returnCode)
								{
									// ackファイル作成を再試行するよう制御
									nextProc = NEXTPROC_FILECREATE;
									continue;
								}
							case NEXTPROC_UPLOAD:
								// ファイルサイズチェック送信した
								// ファイルとローカルのファイルサイズチェック
								//作成した監視完了ファイルを転送する。
								// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
								printLog(msgList, "ack upload start(ファイル名：" + this.fileList[0] + ")");
								// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
								// 2011/11/15 ackファイルをディレクトリに転送する対応 FST start
								returnCode = upload(msgList, true);
								// 2011/11/15 ackファイルをディレクトリに転送する対応 FST start

								// v5.00.01 2014/01/14 ackフォルダのackファイルの上書きチェック Start
								if (fileExistFlg)
								{
									// メッセージ用にファイル名退避（delete()後では取得できない）
									String expMsg = "既に同名のファイルが指定のディレクトリに存在しています。" + this.fileList[0];

									// 終了処理後
									delete(msgList);
									delLocalFile(fileList);
									finallyProc();
									paramClear();

									// エラー終了
									throw new JCCFrameworkException(expMsg);
								}
								// v5.00.01 2014/01/14 ackフォルダのackファイルの上書きチェック End

								if(!returnCode)
								{
									// アップロードを再試行するよう制御
									nextProc = NEXTPROC_UPLOAD;
									continue;
								}
								//作成した監視完了ファイルを転送する。
								// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
								printLog(msgList, "ack upload end");
								// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
							case NEXTPROC_SIZECHECK:
								//転送完了後にファイルサイズをチェックする。
								// 2011/11/15 ackファイルのサイズチェックは行わない FST start
								//returnCode = fileSizeCheck(msgList);
								//if(!returnCode)
								//{
								//	// アップロードから再試行するよう制御
								//	nextProc = NEXTPROC_UPLOAD;
								//	continue;
								//}
								// 2011/11/15 ackファイルのサイズチェックは行わない FST end
								break;
							default:
								try{
									// 終了処理
									finallyProc();
									// 待機変数クリア
									paramClear();
								}catch(JCCFrameworkException ex){
								}
								throw new JCCFrameworkException("FTP転送処理中に不明な内部コードが検出されました。");
						}
						// 処理終了を設定
						nextProc = NEXTPROC_END;
					}
					
					// エラーの場合はリトライ回数を
					// 使い果たしているため処理終了
					if(!returnCode){
						break;
					}
				}
				
				// ローカルのackファイル削除
				delLocalFile(fileList);
			}	
			
			if(returnCode)
			{
				// オリジナルファイルパスへ書き換え
				this.fileList = null;
				this.fileList = fileListSave;
				
				// 送信が完了したファイルをバックアップ
				// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
				printLog(msgList, "file backup start");
				returnCode = fileBackUp(msgList);
				printLog(msgList, "file backup end");
				// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 end
				if(!returnCode)
				{
					// バックアップの成功・失敗に関わらず処理終了
				}
			}
		}
		
		// 終了処理
		finallyProc();
		// 待機変数クリア
		paramClear();
		
		// 2013/01/30 FTP接続情報ログ出力 start
		printLog(msgList, (returnCode == true ? "正常終了" : "異常終了"));
		// 2013/01/30 FTP接続情報ログ出力 end
		
		return returnCode;
	}

	/**
	 * FTPからdownloadする
	 */
	private boolean download(HashMap<String, Object> msgList) {
		//処理結果詳細（エラー設定用）
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values1 = {null, false,  "CDコマンドの実行に失敗しました。", "208"};
		Object[] values2 = {null, false,  "転送モードの設定に失敗しました。", "211"};
		Object[] values3 = {null, false,  "一時作業用フォルダ作成に失敗しました。", "203"};
		Object[] values4 = {null, false,  "ダウンロードファイルオープンに失敗しました。", "203"};
		Object[] values5 = {null, false,  "ダウンロードファイル転送に失敗しました。", "203"};
		
		tmpFolderPath = new ArrayList<String>();
		
		//@CDコマンドを実行し、ホストディレクトリパスに移動する
		try {
			if(0 != cd(this.hostDirectory))
			{
				values1[0] = this.fileList[0];
				setDetailMapArrayListFile(keys, values1, new Integer(2));
				return false;
			}
		} catch (JCCFrameworkException e) {
			values1[0] = this.fileList[0];
			setDetailMapArrayListFile(keys, values1, new Integer(2), e);
			return false;
		}
		// 転送モードを指定
		try {
			if(0 != type(this.transferMode))
			{
				values2[0] = this.fileList[0];
				setDetailMapArrayListFile(keys, values2, new Integer(2));
				return false;
			}
		} catch (JCCFrameworkException e) {
			values2[0] = this.fileList[0];
			setDetailMapArrayListFile(keys, values2, new Integer(2), e);
			return false;
		}
		
		String tmpDir = null;
		String workDir = null;
		String workFileName = null;
		File file = null;
		int index = -1;
		boolean fileCheckFlg = true;
		for(int i=0; i < fileList.length; i++){
			//Aフィールドに保持しているファイルリストよりファイル名を取得する。
			//BJCCFileUtil.createDirUid、JCCFileUtil.createFileNameUidメソッドを使用し、一時作業用フォルダを作成する。
			file = new File(fileList[i]);
			if(!file.isFile())
			{
				setDetailMapArrayListNoFile(fileList[i], "307");
				fileCheckFlg = false;
				continue;
			}
			index++;
			tmpDir = file.getParent();
			try
			{
				workDir = JCCFileUtil.createDirUid(tmpDir);
				workFileName= JCCFileUtil.createFileNameUid(workDir);
				JCCFileUtil.createDir(workFileName);
			}
			catch(Exception e)
			{
				//C一時作業用フォルダ作成失敗時は、ArrayList内処理結果詳細Map参照し、	
				//ERR_FLGがtrueの場合は処理結果詳細Mapに以下を上書き、処理結果をfalseに設定して処理を終了する。
				//ERR_FLGがfalseの場合は処理結果をfalseに設定して処理を終了する。（エラー内容を上書かない）
				values3[0] = fileList[i];
				setDetailMapArrayListFile(keys, values3, new Integer(2), e);

				return false;
			}
			
			//D一時作業用フォルダパスをフィールドに保存する。
			tmpFolderPath.add(workDir);
			tmpFolderPathStore.add(workDir);
			
// 2012/08/14 FST)arata Fortify対応 start
			//Eフィールドに保持しているファイルリストよりファイル名を取得する。
			//Fダウンロード用ソケットを取得、RETRコマンドを発行する。
			InputStream in = null;
			Socket dataSocket_retr = null;
			try
			{
				try
				{
					dataSocket_retr = dataConnection("RETR " + file.getName());
					in = dataSocket_retr.getInputStream();
				}
				//Hファイルオープン失敗時は、ArrayList内処理結果詳細Map参照し、
				//ERR_FLGがtrueの場合は処理結果詳細Mapに以下を上書き、処理結果をfalseに設定して処理を終了する。
				//ERR_FLGがfalseの場合は処理結果をfalseに設定して処理を終了する。（エラー内容を上書かない）
				catch (Throwable e)
				{
					values4[0] = fileList[i];
					setDetailMapArrayListFile(keys, values4, new Integer(2), e);
					return false;
				}
				
				//GAで取得したダウンロード対象ファイルを一時作業用フォルダに書き出す
				try
				{
					bytesToFile(tmpFolderPath.get(index) + File.separator + file.getName(),in);
				}
				catch (JCCFrameworkException ex)
				{
					values5[0] = fileList[i];
					setDetailMapArrayListFile(keys, values5, new Integer(2), ex);
					return false;
				}
			}
			finally
			{
				try
				{
					if(dataSocket_retr != null)
					{
						dataSocket_retr.close();
					}
				}
				catch(IOException e)
				{
					throw new JCCFrameworkException(e);
				}
			}
// 2012/08/14 FST)arata Fortify対応 end
		}
		
		//Iファイルリストのファイルをすべてダウンロードした場合は、処理結果をtrueに設定して処理を終了する。
		//未処理のファイルが残っている場合はEから繰り返す。
		return fileCheckFlg;
			
	}

	/**
	 * FTPへuploadする
	 * 
	 */
	private boolean upload(HashMap<String, Object> msgList, boolean upAckFile) {
		
		//処理結果詳細（エラー設定用）
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values1 = {null, false,  "CDコマンドの実行に失敗しました。", "207"};
		Object[] values2 = {null, false,  "転送モードの設定に失敗しました。", "210"};
		Object[] values3 = {null, false,  "アップロードファイルオープンに失敗しました。", "204"};
		Object[] values4 = {null, false,  "アップロードファイル転送に失敗しました。", "204"};
		Object[] values5 = {null, true, null, null, null};

		// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
		printLog(msgList, "upload() CD " + hostDirectory);

		//@CDコマンドを実行し、ホストディレクトリパスに移動する
		try
		{
			if(0 != cd(this.hostDirectory))
			{
				values1[0] = this.fileList[0];
				setDetailMapArrayListFile(keys, values1, new Integer(2));
				return false;
			}
			// 2011/11/15 ackファイルをディレクトリに転送する対応 FST start
			if(upAckFile == true)
			{
				mkdir(EXTEND_ACK);
				String sep = null;
				if(this.hostDirectory.startsWith("/"))
				{
					sep = "/";
				}
				else
				{
					sep = "\\";
				}
				if(0 != cd(this.hostDirectory + sep + EXTEND_ACK))
				{
					values1[0] = this.fileList[0];
					setDetailMapArrayListFile(keys, values1, new Integer(2));
					return false;
				}
			}
			// 2011/11/15 ackファイルをディレクトリに転送する対応 FST end
		}
		catch (JCCFrameworkException e)
		{
			// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
			printLog(msgList, "upload() JCCFrameworkException(CD)：" + e.getMessage());

			values1[0] = this.fileList[0];
			setDetailMapArrayListFile(keys, values1, new Integer(2), e);
			return false;
		}

		// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
		printLog(msgList, "upload() type = " + transferMode);

		// 転送モードを指定
		try {
			if(0 != type(this.transferMode))
			{
				values2[0] = this.fileList[0];
				setDetailMapArrayListFile(keys, values2, new Integer(2));
				return false;
			}
		} catch (JCCFrameworkException e) {
			// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
			printLog(msgList, "upload() JCCFrameworkException(転送モード)：" + e.getMessage());

			values2[0] = this.fileList[0];
			setDetailMapArrayListFile(keys, values2, new Integer(2), e);
			return false;
		}

		// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
		printLog(msgList, "upload() 転送開始");

		OutputStream out = null;
		Socket dataSocket_stor = null;
		File file = null;
		boolean fileCheckFlg = true;
		
		for(int i=0; i < fileList.length; i++){
			//Aフィールドに保持しているファイルリストよりファイル名を取得する。
			//Bアップロード用ソケットを取得し、STORコマンドを発行する。
			//CAで取得したアップロード対象ファイルをストリームに書き込む
			file = new File(fileList[i]);
			
			// 2012/01/04 転送先ファイルの上書きをしない対応 FST start
			String[] tmpList = getFileNameList(this.hostDirectory);
			// ファイルの存在チェックを行い、既に存在している場合は存在フラグを立てる
			if(null != tmpList)
			{
				if(Arrays.asList(tmpList).contains(file.getName()) == true)
				{
					this.fileExistFlg = true;
					return false;
				}
			}
			// 2012/01/04 転送先ファイルの上書きをしない対応 FST end

			// v5.00.01 2014/01/14 ackフォルダのackファイルの上書きチェック Start
			if (upAckFile) {
				// ackフォルダ内ファイル名リスト取得
				String sep = hostDirectory.startsWith("/") ? "/" : "\\" ;
				tmpList = getFileNameList(this.hostDirectory + sep + EXTEND_ACK);

				// 重複名称チェック
				if (tmpList != null && Arrays.asList(tmpList).contains(file.getName())) {
					this.fileExistFlg = true;
					return false;
				}
			}
			// v5.00.01 2014/01/14 ackファイルの上書きチェック End

			// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
			printLog(msgList, "upload() ファイル上書きチェックOK：" + file.getPath());

// 2012/08/14 FST)arata Fortify対応 start
			try
			{
				try
				{
					//Dファイルオープン失敗時は、処理結果詳細MapのArrayListに以下のHashMapを追加し、処理結果をfalseに設定して処理を終了する。
					if(!file.isFile())
					{
						setDetailMapArrayListNoFile(fileList[i], "308");
						fileCheckFlg = false;
						continue;
					}
					dataSocket_stor = dataConnection("STOR " + file.getName());
					out = dataSocket_stor.getOutputStream();
					
				
				}
				catch (Throwable e)
				{
					// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
					printLog(msgList, "upload() Throwable(getOutputStream)：" + e.getMessage());

					//E転送失敗時は、処理結果詳細MapのArrayListに以下のHashMapを追加し、処理結果をfalseに設定して処理を終了する。

					values3[0] = fileList[i];
					setDetailMapArrayListFile(keys, values3, new Integer(2), e);
					return false;
				}
				try
				{
					if(!file.isFile())
					{
						setDetailMapArrayListNoFile(fileList[i], "308");
						fileCheckFlg = false;
						continue;
					}
					fileToBytes(fileList[i], out);
				} catch (JCCFrameworkException e)
				{
					// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
					printLog(msgList, "upload() JCCFrameworkException(setDetailMapArrayListNoFile)：" + e.getMessage());

					values4[0] = fileList[i];
					setDetailMapArrayListFile(keys, values4, new Integer(2), e);
					
					return false;
				}
			}
			finally
			{
				try
				{
					if(dataSocket_stor != null)
					{
						dataSocket_stor.close();
					}
				}
				catch(IOException e)
				{
					// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
					printLog(msgList, "upload() IOException(close)：" + e.getMessage());
					throw new JCCFrameworkException(e);
				}
			}
// 2012/08/14 FST)arata Fortify対応 end
			
			//F正常終了の場合は処理結果詳細MapのArrayListに以下のHashMapを追加する。
			values5[0] = fileList[i];
			setDetailMapArrayListFile(keys, values5, new Integer(0));
		}

		// v7.00.00 2014/03/17 FTP接続情報ログ出力追加
		printLog(msgList, "upload() 転送完了：fileCheckFlg = " + fileCheckFlg);

		//Gフィールドに保存しているファイルリストのファイルをすべてアップロードした場合は、処理結果をtrueに設定して処理を終了する。	
		//未処理のファイルが残っている場合はAから繰り返す。
		//一度でも失敗しらら、ERR_KBN を 2 にする。
		if(!fileCheckFlg)
		{
			msgList.put(ERR_KBN, new Integer(2));
		}
		return fileCheckFlg;
	}
	
	/**
	 * FTPサーバのファイルを削除する
	 */
	private boolean delete(HashMap<String, Object> msgList)  {
		
		//処理結果詳細（エラー設定用）
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values1 = {null, false, "CDコマンドの実行に失敗しました。", "209"};
		Object[] values2 = {null, false,  "ファイル削除に失敗しました。", "205"};
		String[] deleteFileList = {""};
		boolean fileCheckFlg = true;
		
		//@CDコマンドを実行し、ホストディレクトリパスに移動する
		
		try
		{
			if(0 != cd(this.hostDirectory))
			{
				values1[0] = this.fileList[0];
				setDetailMapArrayListFile(keys, values1, new Integer(2));
				return false;
			}
		}
		catch(JCCFrameworkException e)
		{
			values1[0] = this.fileList[0];
			setDetailMapArrayListFile(keys, values1, new Integer(2), e);
			return false;
		}
		
		String strFileName = "";
		try
		{
			File file = null;
			String[] res = {""};
			deleteFileList = getFileList(FILE_ERR);
			for(int i=0; i < deleteFileList.length; i++)
			{
				strFileName = deleteFileList[i];
				file = new File(deleteFileList[i]);
				Socket dataSocket_dele = dataConnection("DELE " + file.getName(), res);
				//C削除対象ファイルを削除する。
				if (null != dataSocket_dele) {
					dataSocket_dele.close();
				}
				
				//Dファイル削除失敗時は、ArrayList内処理結果詳細Map参照し、
				//ERR_FLGがtrueの場合は処理結果詳細Mapに以下を上書き、処理結果をfalseに設定して処理を終了する。
				//ERR_FLGがfalseの場合は処理結6果をfalseに設定して処理を終了する。（エラー内容を上書かない）
				if(ERROR.equals(res[0]))
				{
					values2[0] = deleteFileList[i];
					setDetailMapArrayListFile(keys, values2, new Integer(2));
					fileCheckFlg = false;
				}
			}
		}
		catch(Throwable e)
		{
			values2[0] = strFileName;
			setDetailMapArrayListFile(keys, values2, new Integer(2), e);
			return false;
		}
		//Eファイルリストのファイルをすべて削除した場合は、処理結果をtrueに設定して処理を終了する。	
		//未処理のファイルが残っている場合はAから繰り返す。
		return fileCheckFlg;
	}
	
	/**
	 * FTPサーバーへ接続
	 */
	private boolean ftpConnection(HashMap<String, Object> msgList) {
		
		//3.1.2 処理詳細
		//処理結果詳細（エラー設定用）
		String[] keys = {ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values1 = {false,  "ソケット接続に失敗しました。", "200"};
		Object[] values2 = {false,  "ユーザー認証に失敗しました。", "201"};
		Object[] values3 = {false,  "パスワード認証に失敗しました。", "201"};
		Object[] values4 = {true,  null, null, null};
		String mapKey = CONNECT_ERR;
		
		try
		{
			// 2016/1/25 V22.00.00 MOD START
			int timeoutTime = 0;
			
			try {
				timeoutTime = Integer.parseInt(JCMAPLConstMgr.getString("FTP_TIMEOUT"));
			}catch(NumberFormatException ne) {
			}
			printLog(msgList, "コネクションタイムアウト時間（ミリ秒）：" + timeoutTime);

			//@フィールドのポート番号を使用しソケットを作成
//			ctrlSocket = new Socket(this.host,Integer.parseInt(this.port));
			ctrlSocket = new Socket();
			InetSocketAddress inetaddr = new InetSocketAddress(this.host, Integer.parseInt(this.port));
			ctrlSocket.connect(inetaddr,timeoutTime);
//			ctrlSocket.setSoTimeout(TimeoutTime);
			
			// 2016/1/25 V22.00.00 MOD END
			//AローカルのIPアドレスをソケットインスタンスより取得
			this.localHostAddress = ctrlSocket.getLocalAddress().getAddress();
			//Bコマンド入出力用のストリームを確保
			ctrlOutput = new PrintWriter(ctrlSocket.getOutputStream());
			ctrlInput = new BufferedReader(new InputStreamReader(ctrlSocket.getInputStream()));
			//接続時のメッセージを取得する
			ctrlInput.readLine();
			
		}
		catch(Throwable e){
			//C@〜BでSocketException例外が発生した場合は、処理結果詳細Mapに
			// 以下を設定し、処理結果をfalseに設定して処理を終了する。
			setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values1, mapKey, e);
			return false;
		}

		//Dユーザ認証コマンドを実行。認証失敗時は、処理結果詳細Mapに以下を設定し、処理結果をfalseに設定して処理を終了する。
		String sendCommand = "USER " + this.user;
// 2012/08/06 FST)arata windowsサーバー判定 start
		if(windowsSvFlg)
		{
			ctrlOutput.print(sendCommand + WINDOWS_LINE_SEPARATOR);
		}
		else
		{
			ctrlOutput.println(sendCommand);
		}
// 2012/08/06 FST)arata windowsサーバー判定 end
		ctrlOutput.flush();
		
		try
		{
			if(ERROR.equals(receiveMessage(USER))){
				setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values2, mapKey);
				return false;
			}
		}
		catch (JCCFrameworkException e)
		{
			setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values2, mapKey, e);
			return false;
		}
		
		//Eパスワード認証コマンドを実行。認証失敗時は、処理結果詳細Mapに以下を設定し、処理結果をfalseに設定して処理を終了する。
		//処理結果詳細（エラー設定用）
		sendCommand = "PASS " + this.password;
// 2012/08/06 FST)arata windowsサーバー判定 start
		if(windowsSvFlg)
		{
			ctrlOutput.print(sendCommand + WINDOWS_LINE_SEPARATOR);
		}
		else
		{
			ctrlOutput.println(sendCommand);
		}
// 2012/08/06 FST)arata windowsサーバー判定 end
		ctrlOutput.flush();
		
		try {
			if(ERROR.equals(receiveMessage(PASS))){
				setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values3, mapKey);
				return false;
			}
		} catch (JCCFrameworkException e) {
			setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values3, mapKey, e);
			return false;
		}
		
		//F正常終了の場合は処理結果詳細Mapに以下を設定し、処理結果をtrueに設定して処理を終了する。
		setDetailMapHashMap(msgList, ERR_KBN, new Integer(0), keys, values4, mapKey);
		return true;
	}

	/**
	 * FTPサーバーの接続を閉じる
	 */
	private boolean ftpConnectionClose(HashMap<String, Object> msgList) {

		//処理結果詳細（エラー設定用）
		String[] keys = {ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values = {false,  "切断に失敗しました。", "206"};
		String mapKey = CONNECT_ERR;
		
		//@切断コマンドを発行する。
		if(null != ctrlOutput)
		{
			String sendCommand = "QUIT";
// 2012/08/06 FST)arata windowsサーバー判定 start
			if(windowsSvFlg)
			{
				ctrlOutput.print(sendCommand + WINDOWS_LINE_SEPARATOR);
			}
			else
			{
				ctrlOutput.println(sendCommand);
			}
// 2012/08/06 FST)arata windowsサーバー判定 end
			ctrlOutput.flush();
		}
		//B切断失敗時は、処理結果詳細Mapを参照し、	
		//ERR_FLGがtrueの場合は処理結果詳細Mapに以下を上書き、処理結果をfalseに設定して処理を終了する。
		//ERR_FLGがfalseの場合は処理結果をfalseに設定して処理を終了する。（エラー内容を上書かない）
		try {
			if(null != ctrlInput && ERROR.equals(receiveMessage(QUIT)))
			{
				if(TRUE.equals(msgList.get(ERR_FLG)))
				{
					setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values, mapKey);
				}
				return false;
				
			}
		} catch (JCCFrameworkException e) {
			setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values, mapKey, e);
			return false;
		}
		if(null != ctrlOutput){
			ctrlOutput.close();
		}
		try
		{
			if(null != ctrlInput){
				ctrlInput.close();
			}
			if(null != ctrlSocket){
				ctrlSocket.close();
			}
		}
		catch(IOException e)
		{
			setDetailMapHashMap(msgList, ERR_KBN, new Integer(1), keys, values, mapKey, e);
			return false;
		}
		//C正常終了の場合は処理結果をtrueに設定して処理を終了する。
		//(処理結果詳細Mapには接続時の成功情報が書き込まれているため改めて上書きを行わない)	
		return true;
	}
	
	/**
	 * リモートホストの指定したディレクトリに移動
	 */
	private int cd(String dir){

		String sendCommand = "";

		// 指定したディレクトリに移動
		sendCommand = "CWD " + dir;
// 2012/08/06 FST)arata windowsサーバー判定 start
		if(windowsSvFlg)
		{
			ctrlOutput.print(sendCommand + WINDOWS_LINE_SEPARATOR);
		}
		else
		{
			ctrlOutput.println(sendCommand);
		}
// 2012/08/06 FST)arata windowsサーバー判定 end
		ctrlOutput.flush();
		
		if(ERROR.equals(receiveMessage(CWD))){
			return 202;
		}
		
		return 0;
	}

	/**
	 * 転送モードの指定
	 */
	private int type(String transfer_mode){

		String sendCommand = "";
		
		// 指定したモードに送信
		sendCommand = "TYPE " + transfer_mode;
// 2012/08/06 FST)arata windowsサーバー判定 start
		if(windowsSvFlg)
		{
			ctrlOutput.print(sendCommand + WINDOWS_LINE_SEPARATOR);
		}
		else
		{
			ctrlOutput.println(sendCommand);
		}
// 2012/08/06 FST)arata windowsサーバー判定 end
		ctrlOutput.flush();
		
		if(ERROR.equals(receiveMessage(COMMAND))){
			return 206;
		}

		return 0;
	}
	
	// 2011/11/15 ackファイルをディレクトリに転送する対応 FST start
	/**
	 * カレントディレクトリに引数名のフォルダを作成
	 * 既にフォルダが存在してもエラーにはしない
	 */
	private void mkdir(String dirName)
	{
		String sendCommand = "MKD " + dirName;
// 2012/08/06 FST)arata windowsサーバー判定 start
		if(windowsSvFlg)
		{
			ctrlOutput.print(sendCommand + WINDOWS_LINE_SEPARATOR);
		}
		else
		{
			ctrlOutput.println(sendCommand);
		}
// 2012/08/06 FST)arata windowsサーバー判定 end
		ctrlOutput.flush();
		
		receiveMessage("");
		
	}
	// 2011/11/15 ackファイルをディレクトリに転送する対応 FST end
	
	
	/**
	 * データ送受信用ソケットを取得
	 */
	private Socket dataConnection(String ctrlcmd){
		String[] str = {""};
		return dataConnection(ctrlcmd, str);
	}
	

	/**
	 * データ送受信用ソケットを取得
	 */
	private Socket dataConnection(String ctrlcmd, String[] response){
		ServerSocket serverDataSocket = null;
		Socket dataSocket = null;
			String cmd = "PASV";

			// PASVモードで接続
// 2012/08/06 FST)arata windowsサーバー判定 start
			if(windowsSvFlg)
			{
				ctrlOutput.print(cmd + WINDOWS_LINE_SEPARATOR);
			}
			else
			{
				ctrlOutput.println(cmd);
			}
// 2012/08/06 FST)arata windowsサーバー判定 end
			ctrlOutput.flush();

			String line = receiveMessage(PASV);
			try
			{
				if(!ERROR.equals(line)){
					// PASVモード可の場合
	
					int port = 0;
					String ip;
					int[] numbers = new int[6];
					String temp;
					
					//PASVコマンド返却値からＩＰアドレスとポート番号を取り出す
					temp=line.substring(line.indexOf("(")+1,line.indexOf(")"));
					String[] spList = temp.split(",");
					for (int i = 0; 6 > i ; i++) {
						numbers[i] = Integer.parseInt(spList[i]);
					}
					
					port = (numbers[4] * 256) + numbers[5];
					ip = numbers[0] + "." + numbers[1] + "." 
					+ numbers[2] + "." + numbers[3];
					
					InetAddress hostAddress = InetAddress.getByName(ip);
					
					dataSocket = new Socket(hostAddress, port);
					
					
				}else{
					//PASVモード不可の場合
					//ACTIVEモード
					
					cmd = "PORT ";
					
					//データコネクション用のSocketサーバーを生成する
					serverDataSocket = new ServerSocket(0,1);
					for (int i = 0; 4 > i; i++) {
						cmd = cmd + (localHostAddress[i] & 0xff) + ",";
					}
					//ポート範囲を計算して設定
					int port = serverDataSocket.getLocalPort();
					int highport = port / 256;
					
					cmd = cmd + ( highport & 0xff) + "," + (port & 0xff);
					
// 2012/08/06 FST)arata windowsサーバー判定 start
					if(windowsSvFlg)
					{
						ctrlOutput.print(cmd + WINDOWS_LINE_SEPARATOR);
					}
					else
					{
						ctrlOutput.println(cmd);
					}
// 2012/08/06 FST)arata windowsサーバー判定 end
					ctrlOutput.flush();
					
					receiveMessage(COMMAND);
				}
// 2012/08/06 FST)arata windowsサーバー判定 start
				if(windowsSvFlg)
				{
					ctrlOutput.print(ctrlcmd + WINDOWS_LINE_SEPARATOR);
				}
				else
				{
					ctrlOutput.println(ctrlcmd);
				}
// 2012/08/06 FST)arata windowsサーバー判定 end
				ctrlOutput.flush();
				if("DELE".equals(getCommand(ctrlcmd)))
				{
					response[0] = receiveMessage(DELE);
				}
				else if("COMMAND".equals(getCommand(ctrlcmd)))
				{
					response[0] = receiveMessage(COMMAND);
				}
				else
				{
					response[0] = receiveMessage(getCommand(ctrlcmd));
				}
				
				if (null != serverDataSocket) {
					dataSocket = serverDataSocket.accept();
//					serverDataSocket.close();
				}
			}
			catch(Throwable e)
			{
// 2012/08/14 FST)arata Fortify対応 start
				try
				{
					if(dataSocket != null)
					{
						dataSocket.close();
					}
				}
				catch(IOException ioe)
				{
				}
// 2012/08/14 FST)arata Fortify対応 end
				throw new JCCFrameworkException("データ送受信用ソケットを取得で例外が発生しました。", e);
			}
// 2012/08/14 FST)arata Fortify対応 start
			finally
			{
				try
				{
					if(serverDataSocket != null)
					{
						serverDataSocket.close();
					}
				}
				catch(IOException e)
				{
					throw new JCCFrameworkException("データ送受信用ソケットを取得で例外が発生しました。", e);
				}
			}
// 2012/08/14 FST)arata Fortify対応 end
			
			return dataSocket;
	}

	/**
	 * 受信メッセージの判断
	 */
	private String receiveMessage(String type){
	
		String res = null;
		//応答メッセージを取得
		try {
			res = ctrlInput.readLine();
		} catch (IOException e) {
			throw new JCCFrameworkException("受信メッセージの判断で例外が発生しました。", e);
		}
		
		if(!isReady(res,type))
		{
			return ERROR; 
		}
		
		return res;

	}

	/**
	 * リターンコードの確認
	 */
	private boolean isReady(String string,String type)
	{
		if(null == string){
			return(false);
		}
		
		if(0 == string.substring(0,3).compareTo(type))
		{
			return(true);
		}
		return(false);
	}

	/**
	 * 実ファイルを読み込んでOutputStreamに書き込み
	 */
	private void fileToBytes(String fileName,OutputStream os){

		// 変数定義
		FileInputStream inStream = null;
		boolean readFlg = true;
		try
		{
			// ファイルの名前を取得（拡張子付）
			File f_filePath = new  File(fileName);
			if(f_filePath.isFile())
			{
				inStream = new FileInputStream(f_filePath);
				int bytes;

				//バッファ読み込みサイズを5120バイトで統一
				byte b[] = new byte[5120];
				while (-1 != (bytes = inStream.read(b))){
					os.write(b, 0, bytes);
				}
				os.flush();
				os.close();
				
				//ファイル転送後のメッセージを読み込む
				if(readFlg)
				{
					ctrlInput.readLine();
				}
				if ( null != inStream) {
					inStream.close();
				}
				
				return;
			}
			else
			{
				readFlg = false;
				throw new JCCFrameworkException("ファイル読み込みに失敗しました。");
			}
		}
		catch(Throwable e)
		{
			try
			{
				if(readFlg)
				{
					ctrlInput.readLine();
				}
				if ( null != inStream) {
					inStream.close();
				}
			}
			catch (IOException ex)
			{
			}
			throw new JCCFrameworkException("ファイル読み込みに失敗しました。",e);
		}
	}

	/**
	 * InputStreamから実ファイルに書き出し
	 */
	private void bytesToFile(String fileName,InputStream is){

		//書き出し用のストリーム
		FileOutputStream fo = null;

		// ファイルの受信＆書き出し
		try
		{
			fo = new FileOutputStream(fileName);

			int bytes;
			//バッファ読み込みサイズを5120バイトで統一
			byte b[] = new byte[5120];
			while (-1 != (bytes = is.read(b))){
				fo.write(b, 0, bytes);
			}

			fo.flush();
			
			//ファイル書き込み後のメッセージを読み込む
			ctrlInput.readLine();
			if ( null != fo) {
				fo.close();
			}
			return;

		}
		catch(Throwable e)
		{
			try
			{
				//ファイル書き込み後のメッセージを読み込む
				ctrlInput.readLine();
				if ( null != fo) {
					fo.close();
				}
			}
			catch (IOException ex)
			{
			}
			throw new JCCFrameworkException("ファイル書き込みに失敗しました。",e);
		}
	}

	/**
	 * 指定したディレクトリから正規表現として指定されたファイルを検索
	 */
	public ArrayList getFileList(String directory, String infileName){

		ArrayList fileNameList = new ArrayList();

		JCCcomFileSearchUtil ins = new JCCcomFileSearchUtil();
		ins.clear();
		String fileName_regex = null;
		
		// ワイルドカード文字として*を正規表現に変換
		if (null != infileName) {
			fileName_regex = infileName;
			fileName_regex = fileName_regex.replace(".", "\\.");
			fileName_regex = fileName_regex.replace("*", ".*");
		}

		//指定されたディレクトリのファイルのみ検索
		File[] files;
		try {
			files = ins.listFiles(directory, fileName_regex, JCCcomFileSearchUtil.FILE, false, 0);
		} catch (Exception e) {
			throw new JCCFrameworkException("getFileList で例外が発生しました。", e);
		}
		for(int i=0 ; i < files.length ; i++){
			//ファイル名
			fileNameList.add(files[i].getName());
		}

		return fileNameList;
	}
	
	/**
	 * ファイルサイズをチェックする
	 */
	private boolean fileSizeCheck(HashMap<String, Object> msgList)
	{
		//Aフィールドに保持しているファイルリストよりファイル名を取得する。
		//処理結果詳細（エラー設定用）
		// HashMap情報を取得
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values1 = {null, false,  "ファイルサイズ不一致です。", "303"};

		//@ローカルの一時ファイルディレクトリに、転送したファイルをすべてダウンロードする。（FTPダウンロード機能（3.4項））
		// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
		printLog(msgList, "download start");
		// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
		if (!download(msgList))
		{
			return false;
		}
		// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
		printLog(msgList, "download end");
		// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start

		//B一時作業ディレクトリよりファイル名を取得する。
		//Cフィールドに保持しているファイルリスト内のファイルと一時作業ディレクトリ内のファイルのサイズを比較する。
		int checkIndex = 0;
		String tmpFilePath = null;
		File listFile = null;
		int index = -1;
		boolean fileCheckFlg = true;
		for(int i = 0; i < fileList.length; i++)
		{
			listFile = new File(fileList[i]);
			if(!listFile.isFile())
			{
				setDetailMapArrayListNoFile(fileList[i], "310");
				fileCheckFlg = false;
				continue;
			}
			index++;
			tmpFilePath = tmpFolderPath.get(index) + File.separator + listFile.getName();
			try
			{
				// 2012/11/28 FST_mukuo) ファイルサイズを1byteオーダーの単位で比較する start
//				if(Integer.parseInt(JCCFileUtil.getFileSize(fileList[i]))
//						!= Integer.parseInt(JCCFileUtil.getFileSize(tmpFilePath)))
				if(new File(fileList[i]).length() != new File(tmpFilePath).length())
				{
				// 2012/11/28 FST_mukuo) ファイルサイズを1byteオーダーの単位で比較する end
					checkIndex++;
					values1[0] = fileList[i];
					setDetailMapArrayListFile(keys, values1, new Integer(2));
				}
				// 2013/01/30 FTP接続情報ログ出力 start
				printLog(msgList, "ローカルファイルサイズ：" + new File(fileList[i]).length() + "byte／アップロードファイルサイズ：" + new File(tmpFilePath).length() + "byte");
				// 2013/01/30 FTP接続情報ログ出力 end

				
			}
			catch (Throwable e)
			{
				checkIndex++;
				
				values1[0] = fileList[i];
				setDetailMapArrayListFile(keys, values1, new Integer(2), e);
				
			}
		}
		
		if(0 == checkIndex)
		{
			for(String s : tmpFolderPath)
			{
				
				try
				{
					JCCFileUtil.removeDir(s);
				}
				catch (JCCFrameworkException e)
				{
				}
				
			}
			if(!fileCheckFlg)
			{
				msgList.put(ERR_KBN, new Integer(2));
			}
			return fileCheckFlg;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 処理結果詳細Mapを設定する
	 */
	private void setDetailMapHashMap(HashMap<String, Object> msgList, String kbn, Integer kbnValue, String[] keys, Object[] values, String mapKey)
	{
		
		if(null == kbn | null == keys)
		{
			return;
		}
		
		HashMap<String, Object> map = null;
		if(null == msgList.get(mapKey))
		{
			map = new HashMap<String, Object>();
		}
		else
		{
			map = (HashMap<String, Object>)msgList.get(mapKey);
			if (!TRUE.equals(map.get(ERR_FLG)))
			{
				return;
			}
		}
		
		for(int i = 0; i < keys.length; i++)
		{
 			map.put(keys[i], values[i]);
		}
		msgList.put(kbn, kbnValue);
		msgList.put(mapKey, map);

	}
	
	/**
	 * 処理結果詳細Mapを設定する
	 */
	private void setDetailMapArrayListAdd(HashMap<String, Object> msgList, String kbn, Integer kbnValue, String[] keys, Object[] values, String mapKey)
	{
		if(null == kbn | null == keys)
		{
			return;
		}
		
		msgList.put(kbn, kbnValue);
		HashMap<String, Object> map = new HashMap<String, Object>();
		ArrayList<HashMap<String, Object>> list = null;
		if(null == msgList.get(mapKey))
		{
			list = new ArrayList<HashMap<String, Object>>();
		}
		else
		{
			list = (ArrayList<HashMap<String, Object>>)msgList.get(mapKey);
		}
		
		for(int i = 0; i < keys.length; i++)
		{
			map.put(keys[i], values[i]);
		}
		list.add(map);
		msgList.put(mapKey, list);

	}
	
	/**
	 * 処理結果詳細Mapを設定する
	 */
	private void setDetailMapArrayListSet(HashMap<String, Object> msgList, String kbn, Integer kbnValue, String[] keys, Object[] values, String mapKey)
	{
		if(null == kbn | null == keys)
		{
			return;
		}
		
		msgList.put(kbn, kbnValue);
		HashMap<String, Object> map = new HashMap<String, Object>();
		ArrayList<HashMap<String, Object>> list = null;
		if(null == msgList.get(mapKey))
		{
			list = new ArrayList<HashMap<String, Object>>();
		}
		else
		{
			list = (ArrayList<HashMap<String, Object>>)msgList.get(mapKey);
		}
		
		for(int i = 0; i < keys.length; i++)
		{
			map.put(keys[i], values[i]);
		}
		
		HashMap<String, Object> mapWork = new HashMap<String, Object>();
		
		for(int i = 0; i < list.size(); i++)
		{
			mapWork = list.get(i);
			if(((String)values[0]).equals(mapWork.get(FILE_NAME)))
			{
				list.set(i, map);
				break;
			}
		}
		
		msgList.put(mapKey, list);

	}

	/**
	 * FILE_ERR の時に、処理詳細 Map にエラー情報を詰め込む
	 * 
	 * @param keys 処理対象のファイル名
	 * @param values 設定するエラーコード
	 */
	private void setDetailMapArrayListFile(String[] keys, Object[] values, Integer errKbn)
	{
		HashMap<String, Object> mapWork = isMapKeyCheck(FILE_ERR, (String)values[0]);
		
		if(mapWork.containsKey(FILE_NAME))
		{
			if(TRUE.equals(mapWork.get(ERR_FLG))){
				setDetailMapArrayListSet(msgList, ERR_KBN, errKbn, keys, values, FILE_ERR);
			}
		}
		else
		{
			setDetailMapArrayListAdd(msgList, ERR_KBN, errKbn, keys, values, FILE_ERR);
		}
	}
	
	
	/**
	 * ファイルが存在しないときに、処理詳細 Map にエラー情報を詰め込む
	 * 
	 * @param fileName 処理対象のファイル名
	 * @param errorCode 設定するエラーコード
	 * @return mapWork HashMapの情報
	 */
	private void setDetailMapArrayListNoFile(String fileName, String errorCode)
	{
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values = {null, false,  "ファイルが存在しません。", null};
		
		values[0] = fileName;
		values[3] = errorCode;
		
		setDetailMapArrayListFile(keys, values,new Integer(2));
	}
	
	/**
	 * 後処理をする
	 */
	private void finallyProc()
	{
		Throwable[] thrws = new Throwable[4];
		
		//(8) 後処理　（通常時、異常時、例外時いずれの場合も本処理を実行する。）
		//@FTPが接続されている場合は、FTP切断処理（3.2項）を実施する。
		ftpConnectionClose(msgList);
		
		//A一時作業フォルダが存在する場合はフォルダを削除する。
		File file = null;
		for(String s: tmpFolderPathStore)
		{
			try
			{
				file = new File(s);
				if(file.exists())
				{
					JCCFileUtil.removeDir(s);
				}
			}
			catch (JCCFrameworkException e)
			{
				thrws[0] = e;
			}
		}

		//Bソケットがオープンしている場合はクローズする。
		if(null != ctrlSocket)
		{
			try
			{
				ctrlSocket.close();
			}
			catch (IOException e)
			{
				thrws[1] = e;
			}
		}
		//Cストリームがオープンしている場合はクローズする。
		if(null != ctrlInput )
		{
			try
			{
				ctrlInput.close();
			}
			catch (IOException e)
			{
				thrws[2] = e;
			}
		}
		if(null != ctrlOutput)
		{
// 2012/08/23 FST)arata 製造品質チェック対応 start
//			try
//			{
				ctrlOutput.close();
//			}
//			catch (IOException e)
//			{
//				thrws[3] = e;
//			}
// 2012/08/23 FST)arata 製造品質チェック対応 end
		}
		// 後処理のうち、1件でもエラーが発生した場合は例外をTHROW
		if(null != thrws[0] || null != thrws[1] || null != thrws[2] || null != thrws[3]){
			throw new JCCFrameworkException("後処理に失敗しました。", thrws);
		}
		
		// 2013/01/30 FTP接続情報ログ出力 start
		if(null != msgList.get(ERR_KBN))
		{
			HashMap outMap = null;
			printLog(msgList, "ERR_KBN：" + msgList.get(ERR_KBN).toString());
			if((Integer)msgList.get(ERR_KBN) == 1)
			{
				outMap = (HashMap)msgList.get(CONNECT_ERR);
				if(null != outMap)
				{
					printLog(msgList,CONNECT_ERR);
					if(null != outMap.get(ERR_MESSAGE))
					{
						printLog(msgList,"ERR_MESSAGE：" + outMap.get(ERR_MESSAGE).toString());
					}
					if(null != outMap.get(ERR_CD))
					{
						printLog(msgList,"ERR_CD：" + outMap.get(ERR_CD).toString());
					}
				}
			}
			else if((Integer)msgList.get(ERR_KBN) == 2)
			{
				printLog(msgList,FILE_ERR);
				ArrayList<HashMap> arrayMap = (ArrayList<HashMap>)msgList.get(FILE_ERR);
				if(null != arrayMap)
				{
					for(int i = 0; i < arrayMap.size(); i++)
					{
						outMap = arrayMap.get(i);
						if(null != outMap.get(FILE_NAME))
						{
							printLog(msgList,"FILE_NAME：" + outMap.get(FILE_NAME).toString());
						}
						if(null != outMap.get(ERR_MESSAGE))
						{
							printLog(msgList,"ERR_MESSAGE：" + outMap.get(ERR_MESSAGE).toString());
						}
						if(null != outMap.get(ERR_CD))
						{
							printLog(msgList,"ERR_CD：" + outMap.get(ERR_CD).toString());
						}
					}
				}
			}
		}
		// 2013/01/30 FTP接続情報ログ出力 end
	}
	
	/**
	 * 待機変数を初期化する
	 */
	private void paramClear()
	{
		this.localHostAddress = null;
		this.host = null;
		this.port= null;
		this.user= null;
		this.password= null;
		this.retryInterval= 0;
		this.retryCountUni= 0;
		this.retryCountGen= 0;
		this.transferMode = null;
		this.hostDirectory = null;
		this.fileList = null;
		this.msgList = null;
	}
	
	/**
	 * 受信コードを取得する
	 */
	private String getCommand(String command)
	{
		String commandCode = "";
		for(int i = 0; i < RECEIVECODE.length; i++)
		{
			if(0 <= command.indexOf(RECEIVECODE[i]))
			{
				commandCode = RECEIVECODE[i];
				break;
			}
		}
		return commandCode;
	}
	
	/**
	 * HashMap情報の取得.<BR>
	 * ArrayListに格納されているHashMap情報を取得する。
	 * 
	 * @param マップキー値
	 * @return mapWork HashMapの情報
	 */
	private HashMap<String, Object> isMapKeyCheck(String mapKey, String fileName)
	{
		ArrayList<HashMap<String, Object>> list = null;
		HashMap<String, Object> mapWork = null;
		
		// 配列に格納されているHashMapを取得
		list = (ArrayList<HashMap<String, Object>>)msgList.get(mapKey);
		if(msgList.containsKey(mapKey) && null != list)
		{
			boolean findFlg = false;
			for(int i = 0; i < list.size(); i++)
			{
				mapWork = (HashMap<String, Object>)list.get(i);
				if(fileName.equals(mapWork.get(FILE_NAME)))
				{
					findFlg = true;
					break;
				}
			}
			if(!findFlg)
			{
				mapWork = new HashMap<String, Object>();
			}
		}
		else
		{
			mapWork = new HashMap<String, Object>();
		}
		
		return mapWork;
	}
	
	/**
	 * 処理詳細マップからファイルリストを取得する
	 * 
	 * @param マップキー値
	 * @return fileArray ファイルリストのサイズ
	 */
	private String[] getFileList(String mapKey)
	{
		ArrayList<HashMap<String, Object>> list = null;
		HashMap<String, Object> mapWork = null;
		ArrayList<String> fileList = new ArrayList<String> ();
		
		// 配列に格納されているHashMapを取得
		list = (ArrayList<HashMap<String, Object>>)msgList.get(mapKey);
		if(msgList.containsKey(mapKey) && null != list)
		{
			for(int i = 0; i < list.size(); i++)
			{
				mapWork = (HashMap<String, Object>)list.get(i);
				fileList.add((String)mapWork.get(FILE_NAME));
			}
		}
		String[] fileArray = new String[fileList.size()];
		for(int i = 0; i < fileList.size(); i++)
		{
			fileArray[i] = fileList.get(i);
		}
		return fileArray;
	}
	
	/**
	 * ローカルファイルの削除.<BR>
	 * ack拡張子ファイルの削除時に呼び出される。
	 * 
	 * @param ackFilePath ack拡張子ファイルが格納されているパス
	 */
	private void  delLocalFile(String[] ackFilePath)
	{
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values = {null, false,  "ファイル削除に失敗しました。", "205"};
		String[] ackFileList = new String[ackFilePath.length];
		int cnt = 0;
		try
		{
			for (cnt = 0; cnt < ackFilePath.length; cnt++)
			{
				ackFileList[cnt] = chgExtention(ackFilePath[cnt], EXTEND_ACK);
				File file = new File(ackFileList[cnt]);
				if(file.exists())
				{
					JCCFileUtil.removeDir(ackFileList[cnt]);
				}
			}
		}
		catch (JCCFrameworkException e)
		{
			values[0] = ackFileList[cnt];
			setDetailMapArrayListFile(keys, values, new Integer(2), e);
		}
	}
	
	/**
	 * 指定されたファイル情報をHashMapから削除<BR>
	 * 
	 * @param txtFilePath ファイルパス
	 * @return 処理結果 
	 */
	private boolean fileInfoClear(String filePath)
	{
		ArrayList<HashMap<String, Object>> list = null;
		ArrayList<HashMap<String, Object>> listWk = new ArrayList<HashMap<String, Object>>();
		HashMap<String, Object> map = null;
		HashMap<String, Object> mapWork = null;
		Object kbn = null;
		
		// 配列に格納されているHashMapを取得
		list = (ArrayList<HashMap<String, Object>>)msgList.get(FILE_ERR);
		boolean findFlg = false;
		// FILE_ERRの削除
		if(msgList.containsKey(FILE_ERR) && null != list)
		{
			for(int i = 0; i < list.size(); i++)
			{
				mapWork = (HashMap<String, Object>)list.get(i);
				// 処理対象以外のファイルを退避
				if(!filePath.equals(mapWork.get(FILE_NAME)))
				{
					listWk.add(mapWork);
				}
			}
			
			msgList.remove(FILE_ERR);
			if(null != listWk && 0 != listWk.size()){
				// 処理対象以外のファイルのみ詰め替え
				msgList.put(FILE_ERR, listWk);
			}
		}
		
		// CONNECT_ERRの削除
		map = (HashMap<String, Object>)msgList.get(CONNECT_ERR);
		if(msgList.containsKey(CONNECT_ERR) && null != map)
		{
			// ERR_FLGがtrueでない場合
			if (!TRUE.equals(map.get(ERR_FLG)))
			{
				msgList.remove(CONNECT_ERR);
			}
		}
		
		// ERR_KBNの削除
		kbn = msgList.get(ERR_KBN);
		if(msgList.containsKey(ERR_KBN) && null != kbn)
		{
			msgList.remove(ERR_KBN);
		}
		
		return findFlg;
	}
	
	/**
	 * テキストファイルパスからACKファイルパスを生成<BR>
	 * 
	 * @param txtFilePath テキストファイルパス
	 */
	private String chgExtention(String txtFilePath, String extention)
	{
//		String ackFilePath = "";
		String Extention = extention;
// ackファイルの拡張子は二重拡張子にする 2011/01/05 start
//		int lastIndex = 0;
//		
//		lastIndex = txtFilePath.lastIndexOf(".");
//		if(0 <= lastIndex)
//		{
//			ackFilePath = txtFilePath.substring(0, lastIndex);
//		}
//		else
//		{
//			ackFilePath = txtFilePath;
//		}
		
		if(null != extention && !"".equals(extention)){
			Extention = "." + Extention;
		}
		
//		return ackFilePath + Extention;
		return txtFilePath + Extention;
		// ackファイルの拡張子は二重拡張子にする 2011/01/05 end
		
	}
	
	
	/**
	 * ファイルバックアップ処理<BR>
	 * ファイル格納フォルダの直下にフォルダを作成し(フォルダ名「bk」)ファイルを移動する。
	 * 
	 * @return 処理結果
	 */
	private boolean fileBackUp(HashMap<String, Object> msgList)
	{
		//(7)ファイルバックアップ処理（リトライ回数がthis.retryCountより小さい場合のみ）
		//@FTP転送に成功した場合、ファイル格納フォルダの直下にフォルダを作成し(フォルダ名「bk」)ファイルを移動する。
		//Aファイル移動に成功した場合は、処理結果をtrueに設定して処理を終了する。
		//Bファイル移動失敗時は、ArrayList内処理結果詳細Map参照し、
		//ERR_FLGがtrueの場合は処理結果詳細Mapに以下を上書き、処理結果をfalseに設定して処理を終了する。
		//RR_FLGがfalseの場合は処理結果をfalseに設定して処理を終了する。（エラー内容を上書かない）
		
		String dirName = null;
		String newFileName = null;
		//処理結果詳細（エラー設定用）
		String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
		Object[] values = {null, false,  "ファイルバックアップに失敗しました。", "302"};
		File listDir = null;
		File newFile = null;
		
		String filePath = "";
		
		try
		{
			for(int i = 0; i < this.fileList.length; i++)
			{
				filePath = this.fileList[i];
				
				listDir = new File(filePath);
				if(!listDir.isFile())
				{
					setDetailMapArrayListNoFile(filePath, "306");
					return false;
				}
				dirName = listDir.getParent() + File.separator + "bk";
				
				
				// 2012/05/22 バックアップファイルに現在日時を付与する start
				newFileName = dirName + File.separator + this.nowDtm + "_" + listDir.getName();
				// 2012/05/22 バックアップファイルに現在日時を付与する end
				
				// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
				printLog(msgList, "バックアップファイル名：" + newFileName);
				// 2013/01/30 FST_mukuo) FTP接続情報ログ出力 start
				
				File workDir = new File(dirName);
				
				if(!workDir.exists())
				{
					JCCFileUtil.createDir(newFileName);
				}
				newFile = new File(newFileName);
				listDir.renameTo(newFile);
			}
			return true;
		}
		catch(Exception e)
		{
			values[0] = filePath;
			setDetailMapArrayListFile(keys, values, new Integer(2), e);
			return false;
		}
	}
	
	/**
	 * ローカルACKファイル作成処理<BR>
	 * ファイル格納フォルダの直下にACKファイルを作成する。
	 * 
	 * @return 処理結果
	 */
	private boolean createAckFile(HashMap<String, Object> msgList)
	{
		// 監視完了ファイル転送
		File file = null;
		
		file = new File(fileList[0]);
		try
		{
			file.createNewFile();
			return true;
		}
		catch (IOException e)
		{
			//処理結果詳細（エラー設定用）
			String[] keys = {FILE_NAME, ERR_FLG, ERR_MESSAGE, ERR_CD};
			Object[] values = {null, false,  "監視完了ファイルの生成に失敗しました。", "212"};
			values[0] = fileList[0];
			setDetailMapArrayListFile(keys, values, new Integer(2), e);
			return false;
		}
	}
	
	
	/**
	 * FILE_ERR の時に、処理詳細 Map にエラー情報を詰め込む
	 * 
	 * @param keys 処理対象のファイル名
	 * @param values 設定するエラーコード
	 * @param errKbn エラー区分
	 * @param e Throwable
	 */
	private void setDetailMapArrayListFile(String[] keys, Object[] values, Integer errKbn, Throwable e)
	{
		// detailMessageが設定されている場合
		if(null != e.getMessage()){
			// エラーメッセージにdetailMessageを付加
			values[2] = values[2] + " (ExceptionMessage=" + e.getMessage() + ")";
		}
		
		// 処理詳細Mapエラー設定処理呼び出し
		setDetailMapArrayListFile(keys, values, errKbn);
		
	}
	
	/**
	 * 処理結果詳細Mapを設定する
	 */
	private void setDetailMapHashMap(HashMap<String, Object> msgList, String kbn, Integer kbnValue, String[] keys, Object[] values, String mapKey, Throwable e)
	{
		// detailMessageが設定されている場合
		if(null != e.getMessage()){
			// エラーメッセージにdetailMessageを付加
			values[1] = values[1] + " (ExceptionMessage=" + e.getMessage() + ")";
		}
		
		// 処理詳細Mapエラー設定処理呼び出し
		setDetailMapHashMap(msgList, kbn, kbnValue, keys, values, mapKey);
		
	}
	
	// 2012/01/04 転送先ファイルの上書きをしない対応 FST start
	/**
	 * 指定のディレクトリ内のファイル名のリストを取得します
	 * 
	 * @param ディレクトリ名
	 * @return ファイル名のリスト
	 */
	private String[] getFileNameList(String path) throws JCCFrameworkException
	{
		// 2012/11/28 FST_mukuo)ファイルサイズチェックエラー時に上書き禁止エラーを抑制する start
		if(this.fileExistIgnoreFlg)
		{
			return null;
		}
		// 2012/11/28 FST_mukuo)ファイルサイズチェックエラー時に上書き禁止エラーを抑制する start
		
		
		// ローカル変数
		String[] retList = null;
		Socket ftpData = null;
		OutputStream dataOut = null;
		InputStream  dataIn = null;
		ByteArrayOutputStream result = new ByteArrayOutputStream();
		
		// lsコマンドのコマンド名
		String command = "LIST";
		if(path != null)
		{
			command += " " + path;
		}
		
		try
		{
			// OM-2014-0002865 ログ追加
			printLog(msgList, "getFileNameList() LIST実行前：" + command);
			// コネクションの取得及びLISTコマンドの発行
			ftpData = dataConnection(command);
			// OM-2014-0002865 ログ追加
			printLog(msgList, "getFileNameList() LIST実行後：" + command);
			
			// ストリームの取得
			dataOut = ftpData.getOutputStream();
			dataIn  = ftpData.getInputStream();
			
			byte[] buf = new byte[1024];
			int len = 0;
			
			// ファイルリストの取得
			while((len = dataIn.read(buf)) != -1)
			{
				result.write(buf, 0, len);
			}
			result.flush();
			dataIn.close();
			dataIn = null;
			
			if(ERROR.equals(receiveMessage(TRANSFER)))
			{
				// OM-2014-0002865 ログ追加
				printLog(msgList, "getFileNameList() LIST戻り値エラー：" + TRANSFER);
				throw new JCCFrameworkException("ファイルリスト取得コマンドの発行に失敗しました。");
			}
		}
		catch(IOException ioe)
		{
			// OM-2014-0002865 ログ追加
			printLog(msgList, "getFileNameList() IOException：" + ioe.getMessage());
			throw new JCCFrameworkException(ioe);
		}
		finally
		{
			// コネクション／ストリーム類のクローズ
			try
			{
				if(dataIn != null)
				{
					dataIn.close();
				}
				if(dataOut != null)
				{
					dataOut.close();
				}
				if(ftpData != null)
				{
					ftpData.close();
				}
			}
			catch(Exception e)
			{
				// OM-2014-0002865 ログ追加
				printLog(msgList, "getFileNameList() finally内 Exception：" + e.getMessage());
				throw new JCCFrameworkException(e);
			}
		}
		
		// 取得したリスト（属性等含む）からファイル名のみを抽出
		if(result != null && result.size() != 0)
		{
			// 2012/11/28 FST_mukuo) 改行コード判定のOS依存をやめる start
			//retList = result.toString().split(System.getProperty("line.separator"));
			String resultStr = result.toString();
			if(resultStr.indexOf("\r\n") > 0)
			{
				retList = resultStr.split("\\r\\n");
			}
			else if(resultStr.indexOf("\n") > 0)
			{
				retList = resultStr.split("\\n");
			}
			else
			{
				retList = resultStr.split("\\r");
			}
			//
			for(int i = 0; i < retList.length; i++)
			{
				retList[i] = retList[i].substring(retList[i].lastIndexOf(" ") + 1, retList[i].length());
			}
			// 2012/11/28 FST_mukuo) 改行コード判定のOS依存をやめる end
		}
		else
		{
			return null;
		}
		return retList;
	}
	// 2012/01/04 転送先ファイルの上書きをしない対応 FST end

	/**
	 * ログを出力します
	 * 
	 * @param	msgList	ログ情報
	 * @param	outStr	出力文字列
	 * @return なし
	 */
	private void printLog(HashMap msgList, String outStr) throws JCCFrameworkException
	{
		// バッチアプリケーションからの呼出しの場合
		if(null != msgList.get("FTP_BATCH_LOG_INFO_MAP"))
		{
			try
			{
				// ログ出力情報の取得
				HashMap logInfoMap = (HashMap)msgList.get("FTP_BATCH_LOG_INFO_MAP");
				
				// ログメッセージの上書き
				HashMap logOutputMap = (HashMap)logInfoMap.get(JCMLogCommon.KEY_LOG_OUTPUT_MAP);
				logOutputMap.put(JCMLogCommon.LOG_OUTPUT_CONTENT, outStr);
				logInfoMap.put(JCMLogCommon.KEY_LOG_OUTPUT_MAP, logOutputMap);
				
				// ログ出力
				JCMsvlLogOutputCommon.logging(logInfoMap);
			}
			catch(Throwable th)
			{
				throw new JCCFrameworkException("FTP部品からのログ出力に失敗しました。",th);
			}
		}
		// バッチアプリケーション以外からの呼出しの場合
		else
		{
			JSYLogBase.println(JSYLogBase.EXECUTION, this.getClass(), outStr, "CS0003I", null, null, JSYLogBase.EJB_MODE);
		}
		return;
	}
}
