/*
 * 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.common;

import java.io.BufferedReader;
import java.io.File;
// import java.io.FileFilter;								// 7.0.1.4 (2018/11/26)
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.opengion.fukurou.system.BuildNumber;			// 6.4.2.0 (2016/01/29) hayabusa.common.BuildNumber → fukurou.system.BuildNumber に移動
import org.opengion.fukurou.system.Closer;
import org.opengion.fukurou.util.FileUtil;
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.ZipArchive;			// 6.0.0.0 (2014/04/11) ZIP API変更
import org.opengion.fukurou.xml.HybsXMLSave;
import org.opengion.fukurou.db.DBUtil;

/**
 * システムの自動インストールと自動更新を行います。
 *
 * (1)初期インストール・自動更新(#autoInsUpd)
 *   ①初期自動インストールを行うには、起動時の環境変数にINSTALL_CONTEXTSが
 *     設定されている必要があります。
 *     この環境変数が設定されている場合、システムリソーステーブル(GE12)が存在しなければ、
 *     エンジンがインストールされていないと判断し、自動インストールを行います。
 *     INSTALL_CONTEXTSにge,gfが指定されている場合は、開発環境を含めたフルバージョンが
 *     インストールされます。
 *     geのみが指定されている場合は、コアモジュールであるgeのみがインストールされます。
 *
 *     インストールスクリプトは、
 *      webapps/[CONTEXT]/db/[DBNAME]/xml/install			DBID=DEFAULT
 *      webapps/[CONTEXT]/db/[DBNAME]/xml/update			DBID=DEFAULT
 *     以下にあるXMLファイルが全て実行されます。
 *     また、同時に
 *      webapps/[CONTEXT]/db/common/xml/install				DBID=DEFAULT
 *      webapps/[CONTEXT]/db/common/xml/update				DBID=DEFAULT
 *      webapps/[CONTEXT]/db/resource/xml/install			DBID=RESOURCE	(5.6.7.0 (2013/07/27) 追加)
 *      webapps/[CONTEXT]/db/resource/xml/update			DBID=RESOURCE	(5.6.7.0 (2013/07/27) 追加)
 *     以下にあるデータロードスクリプトも全て実行されます。
 *
 *   ②自動更新については、システムリソーステーブル(GE12)の更新と、各システムの更新の2つがあります。
 *     GE12更新の判断基準は、システムID='**'に格納されているバージョン(同一のGE12を使用し
 *     ているシステムの最大バージョン番号)がアップした場合です。
 *     この場合に、エンジン内部で保持しているXMLファイルよりシステムリソースの再ロードを行います。
 *     各システムの更新の判断基準は、システムID=各システムのバージョン番号がアップされた場合です。
 *
 *     更新スクリプトは、
 *      webapps/[CONTEXT]/db/[DBNAME]/xml/update			DBID=DEFAULT
 *     以下にあるXMLファイルが全て実行されます。
 *     また、同時に
 *      webapps/[CONTEXT]/db/common/xml/update				DBID=DEFAULT
 *      webapps/[CONTEXT]/db/resource/xml/update			DBID=RESOURCE	(5.6.7.0 (2013/07/27) 追加)
 *     以下にあるデータロードスクリプトも全て実行されます。
 *
 * (2)インストール(#install)
 *  自動インストールは、通常は画面からコンテキストのアーカイブを指定して行います。
 *
 *  アーカイブの内容としては、アーカイブの直下がコンテキスト名のフォルダとなっている必要があります。
 *  このコンテキストフォルダをwebapps以下に展開します。
 *
 *  また、Tomcatのコンテキストの設定ファイル、([CONTEXT].xml)が"WEB-INFの直下を配置している必要があります。
 *
 *  このインストールでは、Tomcatに対するコンテキスト定義のXMLファイルの配備及び、
 *  各種DB、データのロードを行います。
 *
 *  インストールスクリプトは、
 *   webapps/[CONTEXT]/db/[DBNAME]/xml/install				DBID=DEFAULT
 *  以下にあるXMLファイルが全て実行されます。
 *  また、同時に
 *   webapps/[CONTEXT]/db/common/xml/install				DBID=DEFAULT
 *   webapps/[CONTEXT]/db/resource/xml/install				DBID=RESOURCE	(5.6.7.0 (2013/07/27) 追加)
 *  以下にあるデータロードスクリプトも全て実行されます。
 *
 * @og.rev 4.3.6.6 (2009/05/15) 新規作成
 * @og.group 初期化
 *
 * @version  4.0
 * @author   Hiroki Nakamura
 * @since    JDK5.0,
 */
public final class SystemInstaller {
	private final Connection defConn;		// 5.6.7.0 (2013/07/27) DBID=DEFAULT  のコネクション
	private final Connection rscConn;		// 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
	private final PrintWriter out;			// 5.1.9.0 (2010/08/01)
	private final String DBNAME;			// 5.5.4.4 (2012/07/20) 共通化 (DBID=DEFAULT のDB名)

	/** エンジン共通パラメータ(SYSTEM_ID='**' KBSAKU='0')のXML ファイルの指定	{@value}	*/
	public static final String GE12_XML = "org/opengion/hayabusa/common/GE12.xml";

	/** エンジン共通パラメータ(SYSTEM_ID='**' KBSAKU='0')のENGINE_INFO 読み取りクエリー	{@value}	*/
	public static final String SEL_MAX_ENG = "select PARAM from GE12"
									+ " where SYSTEM_ID='**'"
									+ " and PARAM_ID='ENGINE_INFO' and KBSAKU='0' and FGJ='1'" ;

	/** エンジン個別(SYSTEM_ID='個別' KBSAKU='0'  CONTXT_PATH='自身')のバージョン情報を取得するクエリー {@value} 4.3.6.6 (2009/05/15) */
	public static final String SEL_SYS_ENG = "select PARAM from GE12"
									+ " where SYSTEM_ID=? and CONTXT_PATH=?"
									+ " and PARAM_ID='ENGINE_INFO' and KBSAKU='0' and FGJ='1'" ;

	private static final String FS			= File.separator ;						// 5.5.4.4 (2012/07/20) static化
//	private static final String APP_BASE	= System.getenv( "APP_BASE" ) + FS;		// 5.5.4.4 (2012/07/20) static化
	private static final String APP_BASE	= StringUtil.nval(System.getenv( "APP_BASE" ),System.getProperty( "APP_BASE" )) + FS; // 5.9.30.2 (2018/03/23)

//	// 7.0.1.4 (2018/11/26) FileFilter を利用して、フォルダの絞り込みを行う。
//	private static final FileFilter INS_FLTR = file -> {
//													if( file.isFile() ) { return true; }
//													final String name = file.getName().toUpperCase( Locale.JAPAN );
//													return file.isDirectory() && ( name.contains( "INSTALL" ) ||  name.contains( "UPDATE" ) );
//												};
//
//	private static final FileFilter UPD_FLTR = file -> {
//													if( file.isFile() ) { return true; }
//													final String name = file.getName().toUpperCase( Locale.JAPAN );
//													return file.isDirectory() && name.contains( "UPDATE" );
//												};

	/**
	 * データベース処理をおこなうに当たり、処理のタイプを指定するための、enum 定義です。
	 * 文字列で扱っていた箇所を、enum と置き換えます。
	 *
	 * @og.rev 5.5.4.4 (2012/07/20) 新規追加
	 */
	private static enum EXEC_TYPE { INSTALL , UPDATE } ;

//	/**
//	 * データベース処理をおこなうに当たり、処理のタイプを指定するための、enum 定義です。
//	 * 文字列で扱っていた箇所を、enum と置き換えます。
//	 *
//	 * @og.rev 5.5.4.4 (2012/07/20) 新規追加
//	 * @og.rev 7.0.1.4 (2018/11/26) FileFilter を利用して、フォルダの絞り込みを行う。
//	 */
//	private static enum EXEC_TYPE {
//		INSTALL( INS_FLTR ) , 
//		UPDATE(  UPD_FLTR ) ;
//
//		private final FileFilter filter ;
//
//		/** コンストラクター
//		 * 
//		 * @param filter ファイルの絞込みに使用するフィルター
//		 */
//		private EXEC_TYPE( final FileFilter filter ) { this.filter = filter; }
//
//		/** ファイルの絞込みに使用するフィルターを返します。
//		 * 
//		 * @return ファイルの絞込みに使用するフィルター
//		 */
//		public FileFilter getFilter() { return filter; }
//	} ;

	/**
	 * システムインストール・更新クラスのコンストラクタです
	 *
	 * なお、このクラスの中の処理で、エラーが発生しても、Connection は、close 等しません。
	 * 呼び出し元で、try ～ finally で、処理してください。
	 *
	 * @og.rev 5.5.4.4 (2012/07/20) VERSIONは、直接 BuildNumber.ENGINE_INFO を使用。
	 * @og.rev 5.6.7.0 (2013/07/27) アプリケーション登録用とリソース登録用のコネクションを分ける
	 * @og.rev 5.9.24.1 (2017/09/08) DB名を出力する
	 *
	 * @param	defConn	アプリケーション登録用コネクション
	 * @param	rscConn	リソース登録用コネクション
	 * @param	out	表示用のWriter
	 */
	public SystemInstaller( final Connection defConn, final Connection rscConn, final PrintWriter out ) {
		this.defConn = defConn;			// 5.6.7.0 (2013/07/27) アプリケーション登録用
		this.rscConn = rscConn;			// 5.6.7.0 (2013/07/27) リソース登録用
		this.out = out;

		// 5.6.7.0 (2013/07/27) ProductName は、DBUtil 経由で取得する。
		DBNAME = DBUtil.getProductName( defConn );						// 5.6.7.0 (2013/07/27) DBID=DEFAULT  のDB名
		out.println( "    Database Information ( " + DBNAME + " )" );	// 5.9.24.1
	}

	/**
	 * システムの初期自動インストール・自動更新を行います。
	 *
	 * 詳細は、クラスドキュメントを参照して下さい。
	 *
	 * @og.rev 5.1.9.0 (2010/08/01) 新規作成
	 * @og.rev 5.5.4.4 (2012/07/20) VERSIONは、直接 BuildNumber.ENGINE_INFO を使用。
	 * @og.rev 7.0.1.4 (2018/11/26) 初期自動インストール(oldMaxVersion == "none")時でも、loadXMLScript(Update)とdbXMLResourceInsert は行う
	 *
	 * @param systemId システムID
	 * @param context コンテキスト名
	 * @param hostUrl ホスト文字列
	 * @throws UnsupportedEncodingException エンコード名 "UTF-8" が存在しなかった場合。
	 * @see   #dbXMLResourceInsert()
	 */
	public void autoInsUpd( final String systemId, final String context, final String hostUrl ) throws UnsupportedEncodingException  {
		final String oldMaxVersion    = getOldMaxVersion();
		final String oldSystemVersion = getOldSystemVersion( systemId, hostUrl );

		out.println( "    System Version Information ( " + systemId + " )" );
		out.println( "      Load Version [ " + BuildNumber.ENGINE_INFO + " ]" );		// 5.5.4.4 (2012/07/20)
		out.println( "        -> Resource Version[ " + oldMaxVersion + " ]" );
		out.println( "        -> System   Version[ " + oldSystemVersion + " ] " );

		// 初期自動インストール
		if( "none".equalsIgnoreCase( oldMaxVersion ) ) {
			out.println( "      !!! openGion ENVIROMENT IS NOT INSTALLED !!!" );

			final String INSTALL_CONTEXTS = System.getenv( "INSTALL_CONTEXTS" );
			if( INSTALL_CONTEXTS == null || INSTALL_CONTEXTS.isEmpty() ) {
				out.println( "        !!! \"INSTALL_CONTEXT\" IS NOT CONFIGURED\" !!!" );
				out.println( "        !!! \"SET ENRIVOMENT PARAMETER NAMED \"INSTALL_CONTEXT\" ON INIT_SCRIPT !!!" );
//				return;

				// 7.0.1.4 (2018/11/26) 初期自動インストール(oldMaxVersion == "none")時でも、loadXMLScript(Update)とdbXMLResourceInsert は行う
				out.println( "      Start Enviroment Update ( " + context + " )" );
				loadXMLScript( EXEC_TYPE.UPDATE , context );
				out.println( "      Completed               ( " + context + " )" );
			}
			else {
				out.println( "      Start Initiall Enviroment Install : install type ( " + INSTALL_CONTEXTS + " )" );
				final String[] insSys = StringUtil.csv2Array( INSTALL_CONTEXTS );
				for( int i=0; i<insSys.length; i++ ) {
					out.println( "        Install    ( " + insSys[i] + " )" );
					loadXMLScript( EXEC_TYPE.INSTALL, insSys[i] );
					out.println( "        Completed  ( " + insSys[i] + " )" );
				}
			}

			out.println( "      Start SystemParameter Reload" );
			dbXMLResourceInsert();
			out.println( "      Completed" );
		}
		// 自動更新
		else {
			if( oldSystemVersion == null || oldSystemVersion.compareTo( BuildNumber.ENGINE_INFO ) < 0 ){		// 5.5.4.4 (2012/07/20)
				out.println( "      Start Enviroment Update ( " + context + " )" );
				loadXMLScript( EXEC_TYPE.UPDATE , context );
				out.println( "      Completed               ( " + context + " )" );
			}

			if( oldMaxVersion == null || oldMaxVersion.compareTo( BuildNumber.ENGINE_INFO ) < 0 ){				// 5.5.4.4 (2012/07/20)
				out.println( "      Start SystemParameter Reload" );
				dbXMLResourceInsert();
				out.println( "      Completed" );
			}
		}
	}

	/**
	 * システムの自動インストールを行います。
	 *
	 * 詳細は、クラスドキュメントを参照して下さい。
	 *
	 * @og.rev 5.1.9.0 (2010/08/01) 新規作成
	 * @og.rev 5.5.4.4 (2012/07/20) FS , APP_BASE を、共通に設定
	 * @og.rev 6.0.0.0 (2014/04/11) ZIP API変更
	 *
	 * @param buildArchive コンテキストのアーカイブファイル
	 */
	public void install( final File buildArchive ) {

		out.println( "      Check Archive File and Enviroment" );

		// アーカイブの存在チェック
		if( !buildArchive.exists() ) {
			out.println( "        !!! Archive File does not exists File=[ " + buildArchive.getAbsolutePath() + "] !!!" );
			out.println( "        !!! Install Aborted !!! " );
			return;
		}

		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
		final String tempDir    = HybsSystem.sys( "REAL_PATH" ) + HybsSystem.sys( "FILE_URL" ) + System.currentTimeMillis() + FS;
		final String ctxtXmlDir = System.getenv( "CATALINA_HOME" ) + FS + "conf" + FS + System.getenv( "ENGINE_NAME" ) + FS + "localhost" + FS;

		// アーカイブを一時ファイルに展開します。
		ZipArchive.unCompress( new File( tempDir ), buildArchive );				// 6.0.0.0 (2014/04/11) ZIP API変更

		// アーカイブの内容チェック
		final File[] ctxts = new File( tempDir ).listFiles();
		// 6.3.9.0 (2015/11/06) null になっている可能性がある(findbugs)
		if( ctxts != null ) {
			for( final File ctxt : ctxts ) {
				// 5.1.9.0 (2010/08/01) if の条件を入れ替えます。(Avoid if(x != y) ..; else ..;)
				final String context = ctxt.getName();
				if( ctxt.isDirectory() ) {
					// アーカイブ中に[CONTEXT].xmlが存在していない場合はエラー(何も処理しない)
					final File srcCtxtXml = new File( tempDir + context + FS + "WEB-INF" + FS + context + ".xml" );
					if( !srcCtxtXml.exists() ) {
						out.println( "        !!! Context XML Does not exists =[ " + srcCtxtXml.getAbsolutePath() + "] !!!" );
						out.println( "        !!! Install Aborted !!! " );
						return;
					}

					// [CONTEXT].xmlが既に存在している場合はエラー(何も処理しない)
					final File ctxtXml = new File( ctxtXmlDir + context + ".xml" );
					if( ctxtXml.exists() ) {
						out.println( "        !!! Context XML File Already Installed File=[ " + ctxtXml.getAbsolutePath() + "] !!!" );
						out.println( "        !!! Install Aborted !!! " );
						return;
					}

					// webapps/[CONTEXT]が既に存在している場合はエラー(何も処理しない)
					final File webAppsDir = new File( APP_BASE + context );
					if( webAppsDir.exists() ) {
						out.println( "        !!! Context Path Already Exists Path=[ " + webAppsDir.getAbsolutePath() + "] !!!" );
						out.println( "        !!! Install Aborted !!! " );
						return;
					}

					out.println( "        This Archive includes SYSTEM ( " + context + " ) for Install" );			// 5.5.4.4 (2012/07/20)
				}
				// ファイルが含まれている場合はエラー(何も処理しない)
				else {
					out.println( "        !!! This Archive is not Installer. Because include FILE not DIRECTORY. File=[ " + context + "] !!!" );	// 5.5.4.4 (2012/07/20)
					out.println( "        !!! Install Aborted !!! " );
					return;
				}
			}

			// アーカイブをコンテキストファイル以下にコピー
			for( final File ctxt : ctxts ) {
				final String context = ctxt.getName();
				out.println( "      Start Enviroment Install ( " + context + " )" );

				// コンテキストのファイルをコピーします。
				FileUtil.copyDirectry( tempDir + context, APP_BASE + context );

				// [CONTEXT].xmlをTomcatのconf以下に展開します。
				FileUtil.copy( tempDir + context + FS + "WEB-INF" + FS + context + ".xml", ctxtXmlDir + context + ".xml" );

				// DBスクリプトをロードします。
				loadXMLScript( EXEC_TYPE.INSTALL , context );
				out.println( "      Completed                ( " + context + " )" );
			}
		}
		out.println( "      Install Process All Completed." );
	}

	/**
	 * インストール、更新用のXMLスクリプトをロードします。
	 *
	 * @og.rev 5.0.0.2 (2009/09/15) .xmlファイル以外は読み込まないように修正
	 * @og.rev 5.1.1.0 (2009/12/01) コメントを出して、処理中ということが判る様にします。
	 * @og.rev 5.1.9.0 (2010/08/01) DB非依存の定義・データの読み込み対応
	 * @og.rev 5.5.4.4 (2012/07/20) FS , APP_BASE , DBNAME を、共通に設定
	 * @og.rev 5.6.7.0 (2013/07/27) アプリケーション登録用とリソース登録用のコネクションを分ける
	 *
	 * @param	type	更新タイプ[EXEC_TYPE.INSTALL/EXEC_TYPE.UPDATE]
	 * @param	context	コンテキスト名
	 */
	private void loadXMLScript( final EXEC_TYPE type, final String context ) {
		// DB名からスクリプトを格納しているフォルダを探します。
		final String scriptBase = APP_BASE + context.toLowerCase( Locale.JAPAN ) + FS + "db";
		final File[] dbDir = new File( scriptBase ).listFiles();
		if( dbDir == null || dbDir.length == 0 ) {
			out.println( "             DB Folder not found. [" + scriptBase + "]"  );
			return;
		}

		String scriptPath = null;
		for( int i=0; i<dbDir.length; i++ ) {
			if( DBNAME.indexOf( dbDir[i].getName() ) >= 0 ) {
				scriptPath = dbDir[i].getAbsolutePath();
				break;
			}
		}
		if( scriptPath == null ) {
			out.println( "             !!! Script Folder for [ " + DBNAME + " ] not found !!!" );
			return;
		}

		// webapps/[CONTEXT]/db/[DBNAME]/
		execScripts( type , scriptPath , defConn );		// 5.6.7.0 (2013/07/27) DBID=DEFAULT に登録

		// 5.1.9.0 (2010/08/01) DB非依存の定義・データの読み込み対応
		// webapps/[CONTEXT]/db/common/
		execScripts( type , scriptBase + FS + "common" , defConn );		// 5.6.7.0 (2013/07/27) DBID=DEFAULT に登録

		// 5.6.7.0 (2013/07/27) DBID=RESOURCE に登録
		// webapps/[CONTEXT]/db/resource/
		execScripts( type , scriptBase + FS + "resource" , rscConn );	// 5.6.7.0 (2013/07/27) DBID=RESOURCE に登録
	}

	/**
	 * XMLファイルで定義されたDBスクリプトを実行します。
	 *
	 * 引数のtypeに応じて、処理するフォルダが異なります。
	 *   type=INSTALL の場合は、[scriptPath]/xml/install と、[scriptPath]/xml/update 以下の xml ファイル
	 *   type=それ以外の場合は、[scriptPath]/xml/update 以下の xml ファイル
	 * です。
	 *
	 * 現時点では、scriptPath には、下記の ３種類のアドレスが渡され、それぞれ、登録するコネクションが異なります。
	 *   webapps/[CONTEXT]/db/[DBNAME]/			DBID=DEFAULT
	 *   webapps/[CONTEXT]/db/common/			DBID=DEFAULT
	 *   webapps/[CONTEXT]/db/resource/			DBID=RESOURCE
	 *
	 * @og.rev 5.1.9.0 (2010/08/01) 新規作成
	 * @og.rev 5.5.4.4 (2012/07/20) FS , APP_BASE を、共通に設定
	 * @og.rev 5.5.8.4 (2012/11/22) firebird対応。フォルダ単位commitを行う
	 * @og.rev 5.6.7.0 (2013/07/27) Connection引数追加。リソースとアプリを切り分ける。
	 * @og.rev 5.6.9.2 (2013/10/18) EXEC_SQL のエラー時に Exception を発行しない。
//	 * @og.rev 7.0.1.4 (2018/11/26) FileFilter を利用して、フォルダの絞り込みを行う。
	 *
	 * @param	type		更新タイプ[EXEC_TYPE.INSTALL/EXEC_TYPE.UPDATE]
	 * @param	scriptPath	XMLファイルのあるパス
	 * @param	conn		コネクションオブジェクト
	 */
	private void execScripts( final EXEC_TYPE type, final String scriptPath, final Connection conn ) {
		// webapps/[CONTEXT]/db/[DBNAME]/xml/(install|update) 内のスクリプトを実行します
		final List<String> list = new ArrayList<>();

//		// 7.0.1.4 (2018/11/26) FileFilter を利用して、フォルダの絞り込みを行う。
//		//                    対象フォルダのトップ                  フィルター         ｿｰﾄ   結果   isCopy(コピー中ファイルを含む)
//		FileUtil.getFileList( new File( scriptPath  + FS + "xml" ), type.getFilter() , true, list , true );

		if( type == EXEC_TYPE.INSTALL ) {
			FileUtil.getFileList( new File( scriptPath  + FS + "xml" + FS + "install" ), true, list );
			FileUtil.getFileList( new File( scriptPath  + FS + "xml" + FS + "update"  ), true, list );
		}
		else {
			FileUtil.getFileList( new File( scriptPath  + FS + "xml" + FS + "update"  ), true, list );

			/*******************************************************************************
			 * updateの場合に、更新前のバージョンからの変更スクリプトを実行する機能が必要
			 *******************************************************************************/
		}

		if( ! list.isEmpty() ) {
			String dir1 = null;		// 5.1.1.0 (2009/12/01)
			for( final String name : list ) {
				if( name.endsWith( ".xml" ) ) {		// 5.0.0.2 (2009/09/15)
					final File xml = new File( name );
					// 5.1.1.0 (2009/12/01) 処理中コメント：フォルダ単位に表示
					final String dir2 = xml.getParent();
					if( dir1 == null || !dir1.equalsIgnoreCase( dir2 ) ) {
						out.println( "            processing ... " + dir2 );
						dir1 = dir2;
						Closer.commit( conn );			// 5.6.7.0 (2013/07/27) Connection引数追加
					}

					final Reader reader = FileUtil.getBufferedReader( xml, "UTF-8" );			// 6.2.0.0 (2015/02/27) BufferedReader を２重にしていた。
					final HybsXMLSave save = new HybsXMLSave( conn, xml.getName() );			// 5.6.7.0 (2013/07/27) Connection引数追加
					save.onExecErrException( false );		// 5.6.9.2 (2013/10/18) EXEC_SQL のエラー時に Exception を発行しない。
					save.insertXML( reader );
				}
			}
			Closer.commit( conn );			// 5.6.7.0 (2013/07/27) メソッド内でコミット処理を行う。
			out.println( "            DB Enviroment " + type + "ed , [ " + list.size() + " ] scripts loaded " );
		}
	}

	/**
	 * 最後に起動された際のバージョン番号を取得します。(システムID='**')
	 *
	 * エンジンがまだインストールされていない等の原因でエラーが発生した場合は、
	 * "none"という文字列を返します。
	 *
	 * @og.rev 5.1.1.0 (2009/12/01) 実行エラー時に、rollback を追加(PostgreSQL対応)
	 * @og.rev 5.6.7.0 (2013/07/27) リソース用コネクションから取り出します。
	 * @og.rev 5.7.2.0 (2014/01/10) テーブルが無いのに正常終了するケースがある為、ver の初期値を "none" にしておきます。
	 * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
	 *
	 * @return	バージョン番号
	 */
	private String getOldMaxVersion() {
		// エンジンパラメータのエンジン情報(バージョン番号 + ビルドタイプ)を取得します。
		String				ver 		= "none";				// 5.7.2.0 (2014/01/10) 初期値を null ⇒ "none" へ変更。

		// 6.4.2.1 (2016/02/05) try-with-resources 文
		try( final Statement stmt      = rscConn.createStatement();					// setFetchSize は行わない。(ﾃﾞｰﾀ件数が少ない)
			 final ResultSet resultSet = stmt.executeQuery( SEL_MAX_ENG ) ) {
			while( resultSet.next() ) {
				ver = resultSet.getString(1);
			}
		}
		catch( final SQLException ex ) {		// catch は、close() されてから呼ばれます。
			Closer.rollback( rscConn );			// 5.6.7.0 (2013/07/27)
		}
		return ver;
	}

	/**
	 * 最後に起動された際のバージョン番号を取得します。(システムID=各システム)
	 *
	 * @og.rev 5.1.1.0 (2009/12/01) 実行エラー時に、rollback を追加(PostgreSQL対応)
	 * @og.rev 5.6.7.0 (2013/07/27) リソース用コネクションから取り出します。
	 * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
	 *
	 * @param	systemId	システムID
	 * @param	hostUrl		ホストURL
	 *
	 * @return	バージョン番号
	 */
	private String getOldSystemVersion( final String systemId, final String hostUrl ) {
		// エンジンパラメータのエンジン情報(バージョン番号 + ビルドタイプ)を取得します。
		String				ver 		= null;
		// 6.4.2.1 (2016/02/05) try-with-resources 文
		try( final PreparedStatement pstmt = rscConn.prepareStatement( SEL_SYS_ENG ) ) {	// setFetchSize は行わない。(ﾃﾞｰﾀ件数が少ない)
			pstmt.setString( 1, systemId );
			pstmt.setString( 2, hostUrl );
			try( final ResultSet resultSet = pstmt.executeQuery() ) {
				while( resultSet.next() ) {
					ver = resultSet.getString(1);
				}
			}
		}
		catch( final SQLException ex ) {				// catch は、close() されてから呼ばれます。
			Closer.rollback( rscConn );			// 5.6.7.0 (2013/07/27)
		}
		return ver;
	}

	/**
	 * エンジン内部定義の初期リソース情報をDB(GE12)に登録します。
	 *
	 * 初期リソース情報は、KBSAKU='0' で登録されている情報で、一旦すべて削除
	 * してから、全てのリソース情報を追加するという形をとります。
	 * リソースは、すでに、Oracle XDK により XMLファイル化してあります。
	 * なお、この情報をDB登録する理由は、リソースの設定値を変えたい場合に、
	 * キーが判らない(JavaDOCからしか読み取れない)のでは不便な為に
	 * 用意しておくだけで、内部では SystemData オブジェクトとして定義
	 * されている値を使用するため、このデータベース値は、使用していません。
	 *
	 * @og.rev 4.3.6.6 (2009/05/15) バージョン判定部分を分離
	 * @og.rev 5.6.7.0 (2013/07/27) リソース用コネクションに登録します。
	 * @og.rev 5.6.9.2 (2013/10/18) EXEC_SQL のエラー時に Exception を発行しない。
	 *
	 * @throws UnsupportedEncodingException エンコード名 "UTF-8" が存在しなかった場合。
	 */
	private void dbXMLResourceInsert() throws UnsupportedEncodingException {
		// 新設定値を全件INSERTします。
		// common フォルダにセットして、ClassLoader で読み取る方法
		final ClassLoader loader = Thread.currentThread().getContextClassLoader();
		final InputStream stream = loader.getResourceAsStream( GE12_XML );

		final Reader reader = new BufferedReader( new InputStreamReader( stream,"UTF-8" ) );
		final HybsXMLSave save = new HybsXMLSave( rscConn,"GE12" );			// 5.6.7.0 (2013/07/27)
		save.onExecErrException( false );		// 5.6.9.2 (2013/10/18) EXEC_SQL のエラー時に Exception を発行しない。
		save.insertXML( reader );
		final int insCnt = save.getInsertCount();
		final int delCnt = save.getDeleteCount();

		out.print( "        XML Engine Resource Reconfiguration " );
		out.println( "DELETE=[" + delCnt + "],INSERT=[" + insCnt + "] finished." );

		// 5.6.7.0 (2013/07/27) コミットをメソッドの中で処理します。
		Closer.commit( rscConn );
	}
}
