001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.transfer; 017 018import java.io.IOException; 019 020import org.opengion.fukurou.db.Transaction; 021import org.opengion.fukurou.util.StringUtil; 022import org.opengion.fukurou.util.URLConnect; 023 024/** 025 * 伝送要求に対してのHTTP経由で伝送処理を実行します。 026 * 027 * 読取方法により読み取ったデータをPOSTデータとして送信し、リモートホスト上で 028 * 伝送処理を実行します。 029 * 030 * 処理の流れとしては以下のようになります。 031 * @HTTPで伝送処理を実行するためのサーブレットを呼び出す。 032 * A@で呼び出しされたサーブレットが、伝送処理を実行するためのオブジェクトを生成し、 033 * 伝送処理を実行する。 034 * B処理終了後、伝送プロセスに制御が戻り、読取方法に基づく後処理(完了処理または 035 * エラー処理)が実行されます。 036 * 037 * まず@について、呼び出しされるサーブレットは、 038 * [リモート接続先URL]servlet/remoteControl?class=TransferExecWrapper になります。 039 * [リモート接続先URL]は、http://[ホスト名]:[ポート番号]/[コンテキスト名]の形式になりますが、 040 * これについては、実行対象で指定します。 041 * 次にAについて、サーブレット経由で実行される伝送処理について、その実行方法は、 042 * 具体的には、サブクラスのクラス名に対して、このクラス(親クラス)のクラス名+"_" を除外した部分が 043 * 実行方法として認識されます。 044 * 具体的には、クラス名の最後の"_"(アンダーバー)以降が実行方法として認識され、 045 * 例として、サブクラス名がTransferExec_HTTP_CB01の場合、接続先における実行方法は 046 * 旧伝送DB登録(CB01)となります。 047 * また、リモートホスト上で実行される伝送処理の[リモート実行対象]は、元の実行対象で設定します。 048 * このことから、HTTP経由で伝送処理を実行する場合、元の実行対象には、[リモート接続先URL]と 049 * [リモート実行対象]の2つを設定する必要があります。 050 * 具体的な設定方法については各サブクラスのJavaDocを参照して下さい。 051 * 最後にBについて、接続時にエラーが発生した場合や、レスポンスデータに対して"row_error"という 052 * 文字列が存在する場合は、エラーとして処理します。 053 * それ以外の場合は、正常終了として処理します。 054 * 055 * HTTP接続時には、以下のポストデータが送信されます。 056 * [ポストデータ] 057 * ・KBREAD (読取方法) 058 * ・READOBJ (読取対象) 059 * ・READPRM (読取パラメーター) 060 * ・KBEXEC (実行方法) ※サブクラスの最後の"_"(アンダーバー)以降の文字列 061 * ・EXECDBID (実行接続先DBID) 062 * ・EXECOBJ (リモート実行対象) ※ローカルの実行対象からリモート接続先URLを除いた文字列 063 * ・EXECPRM (実行パラメーター) 064 * ・ERROR_SENDTO (読み取り元ホストコード) 065 * ・HFROM (読み取り元ホストコード) 066 * ・n (データ件数) 067 * ・v1〜vn (データ) 068 * 069 * @og.group 伝送システム 070 * 071 * @version 5.0 072 * @author Hiroki.Nakamura 073 * @since JDK1.6 074 */ 075public abstract class TransferExec_HTTP implements TransferExec { 076 077 // リモート制御サーブレット名 078 private static final String REMOTE_SERVLET = "servlet/remoteControl?class=TransferExecWrapper"; 079 080 /** 081 * URL接続を実行します。 082 * 083 * @param vals 伝送データ(配列) 084 * @param config 伝送設定オブジェクト 085 * @param tran トランザクションオブジェクト 086 */ 087 @Override 088 public void execute( final String[] vals, final TransferConfig config, final Transaction tran ) { 089 URLConnect conn = null; 090 try { 091 splitExecObj( config.getExecObj() ); 092 conn = new URLConnect( getRemoteHost() + REMOTE_SERVLET, TransferConfig.HTTP_AUTH_USER_PASS ); 093 if( config.getProxyHost() != null && config.getProxyHost().length() > 0 ) { 094 conn.setProxy( config.getProxyHost(), config.getProxyPort() ); 095 } 096 097 conn.setCharset( "UTF-8" ); 098 // ポストデータを生成します。 099 conn.setPostData( getPostData( vals, config ) ); 100 101 conn.connect(); 102 103 String readData = conn.readData(); 104 // 返されたデータ中に"row_error"が存在する場合はエラーとして処理します。 105 if( readData != null && readData.indexOf( "row_error" ) >= 0 ) { 106 throw new RuntimeException( readData ); 107 } 108 } 109 catch( IOException ex ) { 110 String errMsg = "URL接続時に例外が発生しました。"; 111 throw new RuntimeException( errMsg, ex ); 112 } 113 finally { 114 if( conn != null ) { conn.disconnect(); } 115 } 116 } 117 118 /** 119 * ローカルの実行対象を、リモート接続先の実行対象とリモート接続先URLに分解します。 120 * 121 * @param localExecObj ローカルの実行対象 122 */ 123 protected abstract void splitExecObj( final String localExecObj ); 124 125 /** 126 * リモート接続先URLを返します。 127 * このメソッドは、{@link #splitExecObj(String)}の後に呼び出しする必要があります。 128 * 129 * @return リモート接続先URL 130 */ 131 protected abstract String getRemoteHost(); 132 133 /** 134 * リモート接続先の実行対象を返します。 135 * このメソッドは、{@link #splitExecObj(String)}の後に呼び出しする必要があります。 136 * 137 * @return 接続URL 138 */ 139 protected abstract String getRemoteExecObj(); 140 141 /** 142 * 伝送データ及び伝送設定をPOSTデータとしてシリアライズします。 143 * 144 * @param vals 伝送データ(配列) 145 * @param config 伝送設定オブジェクト 146 * 147 * @return ポストデータ 148 */ 149 private String getPostData( final String[] vals, final TransferConfig config ) { 150 // サブクラス名から親クラス名+"_"を除いた部分を実行方法とする。 151 String kbExec = getClass().getName().replace( getClass().getSuperclass().getName() + "_", "" ); 152 153 StringBuilder buf = new StringBuilder(); 154 buf.append( "KBREAD=" ).append( StringUtil.urlEncode( config.getKbRead() ) ); 155 buf.append( "&READOBJ=" ).append( StringUtil.urlEncode( config.getReadObj() ) ); 156 buf.append( "&READPRM=" ).append( StringUtil.urlEncode( config.getReadPrm() ) ); 157 buf.append( "&KBEXEC=" ).append( StringUtil.urlEncode( kbExec ) ); 158 buf.append( "&EXECDBID=" ).append( StringUtil.urlEncode( config.getExecDbid() ) ); 159 buf.append( "&EXECOBJ=" ).append( StringUtil.urlEncode( getRemoteExecObj() ) ); 160 buf.append( "&EXECPRM=" ).append( StringUtil.urlEncode( config.getExecPrm() ) ); 161 buf.append( "&ERROR_SENDTO=").append( StringUtil.urlEncode( config.getErrorSendto() ) ); 162 buf.append( "&HFROM=" ).append( StringUtil.urlEncode( config.getHfrom() ) ) ; 163 164 if( vals != null && vals.length > 0 ) { 165 buf.append( "&n=" ).append( vals.length ); 166 for( int i=0; i<vals.length; i++ ) { 167 buf.append( "&v" ).append( i ).append( "=" ); 168 buf.append( StringUtil.urlEncode( vals[i] ) ); 169 } 170 } 171 else { 172 buf.append( "&n=0" ); 173 } 174 175 return buf.toString(); 176 } 177}