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 * ②①で呼び出しされたサーブレットが、伝送処理を実行するためのオブジェクトを生成し、
033 *   伝送処理を実行する。
034 * ③処理終了後、伝送プロセスに制御が戻り、読取方法に基づく後処理(完了処理または
035 *   エラー処理)が実行されます。
036 *
037 * まず①について、呼び出しされるサーブレットは、
038 *   [リモート接続先URL]servlet/remoteControl?class=TransferExecWrapper になります。
039 *   [リモート接続先URL]は、http://[ホスト名]:[ポート番号]/[コンテキスト名]の形式になりますが、
040 *   これについては、実行対象で指定します。
041 * 次に②について、サーブレット経由で実行される伝送処理について、その実行方法は、
042 *   具体的には、サブクラスのクラス名に対して、このクラス(親クラス)のクラス名+"_" を除外した部分が
043 *   実行方法として認識されます。
044 *   具体的には、クラス名の最後の"_"(アンダーバー)以降が実行方法として認識され、
045 *   例として、サブクラス名がTransferExec_HTTP_CB01の場合、接続先における実行方法は
046 *   旧伝送DB登録(CB01)となります。
047 *   また、リモートホスト上で実行される伝送処理の[リモート実行対象]は、元の実行対象で設定します。
048 *   このことから、HTTP経由で伝送処理を実行する場合、元の実行対象には、[リモート接続先URL]と
049 *   [リモート実行対象]の2つを設定する必要があります。
050 *   具体的な設定方法については各サブクラスのJavaDocを参照して下さい。
051 * 最後に③について、接続時にエラーが発生した場合や、レスポンスデータに対して"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}