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     */
016    package org.opengion.fukurou.transfer;
017    
018    import java.io.ByteArrayInputStream;
019    import java.io.IOException;
020    import java.util.ArrayList;
021    import java.util.List;
022    
023    import javax.xml.parsers.DocumentBuilder;
024    import javax.xml.parsers.DocumentBuilderFactory;
025    
026    import org.opengion.fukurou.db.Transaction;
027    import org.opengion.fukurou.util.ApplicationInfo;
028    import org.opengion.fukurou.util.StringUtil;
029    import org.opengion.fukurou.util.URLConnect;
030    import org.w3c.dom.Document;
031    import org.w3c.dom.Element;
032    import org.w3c.dom.Node;
033    import org.w3c.dom.NodeList;
034    
035    /**
036     * ä¼é?è¦æ±‚ã«å¯¾ã—ã¦ã€HTTP経由ã§ãƒ??タを読å–ã—ã¾ã™ã?
037     *
038     * èª­å–æ–¹æ³•ã«ã‚ˆã‚Šèª­ã¿å–ã£ãŸãƒ‡ãƒ¼ã‚¿ã‚’POSTãƒ??ã‚¿ã¨ã—ã¦é€ä¿¡ã—ã?リモートã?スト上ã§
039     * ä¼é?処ç?‚’実行ã—ã¾ã™ã?
040     *
041     * 処ç??æµã‚Œã¨ã—ã¦ã¯ä»¥ä¸‹ã?よã†ã«ãªã‚Šã¾ã™ã?
042     * â‘?TTPã§èª­å–å?ç?‚’実行ã™ã‚‹ãŸã‚ã?サーブレãƒ?ƒˆã‚’呼ã³å‡ºã™ã?
043     * â‘¡â‘?§å‘¼ã³å‡ºã—ã•れãŸã‚µãƒ¼ãƒ–レãƒ?ƒˆãŒã?読å–å?ç?‚’実行ã™ã‚‹ãŸã‚ã?オブジェクトを生æ?ã—ã?
044     *   読å–å?ç?‚’実行ã™ã‚‹ã?
045     * ③読å–ã—ãŸçµæžœXMLをパースã—ã?ãã?読å–データをä¼é?ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã«æ¸¡ã—ä¼é?処ç?‚’実行ã™ã‚‹ã?
046     * â‘£ä¼é?処ç?®Ÿè¡Œå¾Œã?â‘¢ã®çµæžœXMLã‹ã‚‰å¾—られる更新キー(é…å?)ã‚’Postãƒ??ã‚¿ã¨ã—ã¦æ¸¡ã—ã?
047     *   HTTP経由ã§å¾Œå?ç?完äº??ç?¾ãŸã?エラー処ç?を実行ã™ã‚‹ã?
048     *
049     * ã¾ãšâ‘ ã«ã¤ã?¦ã€å‘¼ã³å‡ºã—ã•れるサーブレãƒ?ƒˆã¯ã€?
050     *   [リモート接続å?URL]servlet/remoteControl?class=TransferReadWrapper&type=read ã«ãªã‚Šã¾ã™ã?
051     *   [リモート接続å?URL]ã¯ã€http://[ホストå]:[ãƒã?ト番å·]/[コンãƒ?‚­ã‚¹ãƒˆå]ã®å½¢å¼ã«ãªã‚Šã¾ã™ãŒã€?
052     *   ã“れã«ã¤ã?¦ã¯ã€èª­å–å¯¾è±¡ã§æŒ?®šã—ã¾ã™ã?
053     *   接続時ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ãŸå?åˆã‚„ã€ãƒ¬ã‚¹ãƒãƒ³ã‚¹ãƒ??ã‚¿ã«å¯¾ã—ã¦"row_error"ã¨ã?†
054     *   æ–?­—å?ãŒå­˜åœ¨ã™ã‚‹å ´åˆã?ã€ã‚¨ãƒ©ãƒ¼ã¨ã—ã¦å‡¦ç?—ã¾ã™ã?
055     *   ãれ以外ã?å ´åˆã?ã€æ­£å¸¸çµ‚äº?¨ã—ã¦å‡¦ç?—ã¾ã™ã?
056     * 次ã«â‘¡ã«ã¤ã?¦ã€ã‚µãƒ¼ãƒ–レãƒ?ƒˆçµŒç”±ã§è¡Œã‚れるä¼é?処ç?«ã¤ã?¦ã€ãã®èª­å–方法ã?ã€?
057     *   ã“ã?クラスを継承ã—ãŸå?‚µãƒ–クラスã®ã‚¯ãƒ©ã‚¹åã«ã‚ˆã‚Šæ±ºå®šã•れã¾ã™ã?
058     *   具体的ã«ã¯ã€ã‚µãƒ–クラスã®ã‚¯ãƒ©ã‚¹åã«å¯¾ã—ã¦ã€ã“ã®ã‚¯ãƒ©ã‚¹(親クラス)ã®ã‚¯ãƒ©ã‚¹å?"_" を除外ã—ãŸéƒ¨åˆ?Œ
059     *   èª­å–æ–¹æ³•ã¨ã—ã¦èªè­˜ã•れã¾ã™ã?
060     *   例ã¨ã—ã¦ã€ã‚µãƒ–クラスåãŒTransferRead_HTTP_CB01ã®å ´åˆã?接続å?ã«ãŠã‘ã‚‹èª­å–æ–¹æ³•ã?
061     *   æ—§ä¼é?DB読å?CB01)ã¨ãªã‚Šã¾ã™ã?
062     *   ã¾ãŸã?リモートã?スト上ã§å®Ÿè¡Œã•れるä¼é?処ç??[リモート読å–対象]ã¯ã€å?ã®èª­å–対象ã§è¨­å®šã—ã¾ã™ã?
063     *   ã“ã?ã“ã¨ã‹ã‚‰ã€HTTP経由ã§èª­å–å?ç?‚’行ã†å ´åˆã?å…??読å–対象ã«ã¯ã€[リモート接続å?URL]ã¨
064     *   [リモート読å–対象]ã®2ã¤ã‚’設定ã™ã‚‹å¿?¦ãŒã‚りã¾ã™ã?
065     *   具体的ãªè¨­å®šæ–¹æ³•ã«ã¤ã?¦ã¯å?‚µãƒ–クラスã®JavaDocã‚’å‚ç…§ã—ã¦ä¸‹ã•ã??
066     * â‘¢ã«ã¤ã?¦ã€è¿”ã•れるXMLãƒ??ã‚¿ã¯[レスãƒãƒ³ã‚¹ãƒ??ã‚¿ã®XMLæ§‹é?]ã®å½¢å¼ã«ãªã‚Šã¾ã™ã?
067     *   ã“ã“ã§ã€dataListã¯ã€ä¼é?å®Ÿè¡Œã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã«æ¸¡ã•れるデータã«ãªã‚Šã¾ã™ã?
068     *   ã¾ãŸã?keyListã«ã¤ã?¦ã¯ã€ä¼é?実行終äº?¾Œã?HTTP経由ã§å®Œäº??ç?‚’行ã†ãŸã‚ã®æ›´æ–°ã‚­ãƒ¼ã«ãªã‚Šã¾ã™ã?
069     *   (ローカルã®ä¼é?読å–オブジェクトã?トランザクションã«å¯¾ã—ã¦åŒä¸?‚ªãƒ–ジェクトã«ãªã‚Šã¾ã™ãŒã€?
070     *    HTTP接続å?ã§ã‚µãƒ¼ãƒ–レãƒ?ƒˆçµŒç”±ã§ç”Ÿæ?ã•れるã?リモートã?ä¼é?読å–オブジェクトã?ã€?
071     *    読å–å?ç?¨å®Œäº?エラー処ç?§ç•°ãªã‚Šã¾ã™ã?ã“ã?ãŸã‚ã€èª­å–ã—ãŸãƒ‡ãƒ¼ã‚¿ã®ã‚­ãƒ¼ã‚’ローカルã«ä¿æŒã—ã?
072     *    æœ?¾Œã?完äº?エラー処ç??éš›ã«ã€èª­å–ã—ãŸãƒ‡ãƒ¼ã‚¿ã®ã‚­ãƒ¼(更新キー)ã‚’PostDataã¨ã—ã¦æ¸¡ã™ã“ã¨ã§ã€?
073     *    æ­£ã—ã完äº?エラー処ç?Œè¡Œã‚れるよã†ã«å¯¾å¿œã—ã¦ã?¾ã?
074     * æœ?¾Œã«â‘£ã«ã¤ã?¦ã€å‘¼ã³å‡ºã—ã•れるサーブレãƒ?ƒˆã¯ã€?
075     *   [リモート接続å?URL]servlet/remoteControl?class=TransferReadWrapper&type=complete (正常終äº?™‚)
076     *   [リモート接続å?URL]servlet/remoteControl?class=TransferReadWrapper&type=error    (エラー発生時)
077     *   ã¨ãªã‚Šã¾ã™ã?
078     *
079     * HTTP接続時ã«ã¯ã€ä»¥ä¸‹ã?ãƒã‚¹ãƒˆãƒ‡ãƒ¼ã‚¿ãŒé?ä¿¡ã•れã¾ã™ã?
080     * [ãƒã‚¹ãƒˆãƒ‡ãƒ¼ã‚¿]
081     * ・KBREAD                     (èª­å–æ–¹æ³? â€»ã‚µãƒ–ã‚¯ãƒ©ã‚¹ã®æœ?¾Œã?"_"(アンãƒ??ãƒã?)以é™ã?æ–?­—å?
082     * ・READOBJ            (リモート読å–対象) ※ローカルã®èª­å–対象ã‹ã‚‰ãƒªãƒ¢ãƒ¼ãƒˆæŽ¥ç¶šå?URLを除ã?Ÿæ–?­—å?
083     * ・READPRM            (読å–パラメーター)
084     * ・KBEXEC                     (実行方�
085     * ・EXECDBID           (実行接続å?DBID)
086     * ・EXECOBJ            (実行対象)
087     * ・EXECPRM            (実行パラメーター)
088     * ・ERROR_SENDTO       (読ã¿å–りå…??ストコーãƒ?
089     * ・HFROM (読ã¿å–りå…??ストコーãƒ?
090     * ・n (キー件数)
091     * ・k1?žkn (キー)
092     *
093     * ã¾ãŸã?ãƒ??ã‚¿èª­å–æ™‚ã«è¿”ã•れるXMLã¯ä»¥ä¸‹ã?æ§‹é?ã‚’ã—ã¦ã?¾ã™ã?
094     * [レスãƒãƒ³ã‚¹ãƒ??ã‚¿ã®XMLæ§‹é?]
095     * <root>
096     *  <dataList>
097     *   <data>aaa</data>
098     *   <data>bbb</data>
099     *   <data>ccc</data>
100     *   <data>ddd</data>
101     *   <data>eee</data>
102     *  </dataList>
103     *  <keyList>
104     *   <key>KEY1</key>
105     *   <key>KEY2</key>
106     *   <key>KEY3</key>
107     *  </keyList>
108     * </root>
109     *
110     * @og.group ä¼é?シスãƒ?ƒ 
111     *
112     * @version  5.0
113     * @author   Hiroki.Nakamura
114     * @since    JDK1.6
115     */
116    public abstract class TransferRead_HTTP implements TransferRead {
117    
118            // リモート制御サーブレãƒ?ƒˆå?
119            private static final String REMOTE_SERVLET = "servlet/remoteControl?class=TransferReadWrapper";
120    
121            // 更新対象ã®ã‚­ãƒ¼
122            private String[] keys = null;
123    
124            /**
125             * URL接続を行ã„ãƒ??タを読ã¿å–りã¾ã™ã?
126             * 接続パラメータã«ã¯ã€?type=read"ãŒä»˜åŠ ã•れã¾ã™ã?
127             *
128             * @param config ä¼é?設定オブジェクãƒ?
129             * @param tran トランザクションオブジェク�
130             *
131             * @return 読ã¿å–りã—ãŸãƒ??ã‚¿(é…å?)
132             */
133            @Override
134            public String[] read( final TransferConfig config, final Transaction tran ) {
135                    splitReadObj( config.getReadObj() );
136                    String url = getRemoteHost() + REMOTE_SERVLET+ "&type=read";
137                    String postData = getPostData( keys, config );
138                    URLConnect conn = null;
139                    String data = null;
140                    try {
141                            conn = connect( url, postData, config );
142                            data = readData( conn );
143                    }
144                    catch( IOException ex ) {
145                            String errMsg = "URL接続時ã«ä¾‹å¤–ãŒç™ºç”Ÿã—ã¾ã—ãŸã€?URL=" + url + "]";
146                            throw new RuntimeException( errMsg, ex );
147                    }
148                    finally {
149                            if( conn != null ) { conn.disconnect(); }
150                    }
151    
152                    List<String> valList = new ArrayList<String>();
153                    List<String> keyList = new ArrayList<String>();
154    
155                    DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
156                    Document doc = null;
157                    try {
158                            DocumentBuilder builder = dbfactory.newDocumentBuilder();
159                            doc = builder.parse( new ByteArrayInputStream( data.getBytes( "UTF-8" ) ) );
160                    }
161                    catch( Exception ex ) {
162                            String errMsg = "XMLパã?ス時ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€?;
163                            throw new RuntimeException( errMsg, ex );
164                    }
165                    Element root = doc.getDocumentElement();
166    
167                    // ãƒ??タ部åˆ?‚’å–å¾—ã—ã¾ã™ã?
168                    NodeList dataChilds = root.getElementsByTagName( "dataList" ).item(0).getChildNodes();
169                    int numDataChild = dataChilds.getLength();
170                    for( int i=0; i<numDataChild; i++ ) {
171                            Node nd = dataChilds.item(i);
172                            if( nd.getNodeType() == Node.ELEMENT_NODE ) {
173                                    if( "data".equals( ((Element)nd).getTagName() ) )       {
174                                            valList.add( nd.getTextContent() );
175                                    }
176                            }
177                    }
178    
179                    // 以é™ã?処ç?§ãƒ??ã‚¿ã‚’æ›´æ–°ã™ã‚‹ãŸã‚ã®ã‚­ãƒ¼ã‚’å–å¾—ã—ã¾ã™ã?
180                    NodeList keyChilds = root.getElementsByTagName( "keyList" ).item(0).getChildNodes();
181                    int numKeyChild = keyChilds.getLength();
182                    for( int i=0; i<numKeyChild; i++ ) {
183                            Node nd = keyChilds.item(i);
184                            if( nd.getNodeType() == Node.ELEMENT_NODE ) {
185                                    if( "key".equals( ((Element)nd).getTagName() ) )        {
186                                            keyList.add( nd.getTextContent() );
187                                    }
188                            }
189                    }
190    //              keys = keyList.toArray( new String[0] );
191                    keys = keyList.toArray( new String[keyList.size()] );
192    
193    //              return valList.toArray( new String[0] );
194                    return valList.toArray( new String[valList.size()] );
195            }
196    
197            /**
198             * 読å–ã—ãŸãƒ‡ãƒ¼ã‚¿ã«å¯¾ã—ã¦å®Œäº??ç?‚’行ã„ã¾ã™ã?
199             * 接続パラメータã«ã¯ã€?type=complete"ãŒä»˜åŠ ã•れã¾ã™ã?
200             *
201             * @param config ä¼é?設定オブジェクãƒ?
202             * @param tran トランザクションオブジェク�
203             */
204            @Override
205            public void complete( final TransferConfig config, final Transaction tran ) {
206                    splitReadObj( config.getReadObj() );
207                    String url = getRemoteHost() + REMOTE_SERVLET + "&type=complete";
208                    String postData = getPostData( keys, config );
209                    URLConnect conn = null;
210                    try {
211                            conn = connect( url, postData, config );
212                    }
213                    catch( IOException ex ) {
214                            String errMsg = "URL接続時ã«ä¾‹å¤–ãŒç™ºç”Ÿã—ã¾ã—ãŸã€?URL=" + url + "]";
215                            throw new RuntimeException( errMsg, ex );
216                    }
217                    finally {
218                            if( conn != null ) { conn.disconnect(); }
219                    }
220            }
221    
222            /**
223             * 読å–ã—ãŸãƒ‡ãƒ¼ã‚¿ã«å¯¾ã—ã¦ã‚¨ãƒ©ãƒ¼å‡¦ç?‚’行ã„ã¾ã™ã?
224             * 接続パラメータã«ã¯ã€?type=error"ãŒä»˜åŠ ã•れã¾ã™ã?
225             *
226             * @param config ä¼é?設定オブジェクãƒ?
227             * @param appInfo DB接続情報
228             */
229            @Override
230            public void error( final TransferConfig config, final ApplicationInfo appInfo ) {
231                    splitReadObj( config.getReadObj() );
232                    String url = getRemoteHost() + REMOTE_SERVLET + "&type=error";
233                    String postData = getPostData( keys, config );
234                    URLConnect conn = null;
235                    try {
236                            conn = connect( url, postData, config );
237                    }
238                    catch( IOException ex ) {
239                            String errMsg = "URL接続時ã«ä¾‹å¤–ãŒç™ºç”Ÿã—ã¾ã—ãŸã€?URL=" + url + "]";
240                            throw new RuntimeException( errMsg, ex );
241                    }
242                    finally {
243                            if( conn != null ) { conn.disconnect(); }
244                    }
245            }
246    
247            /**
248             * (ã“ã?クラスã§ã¯ã€ã‚µãƒã?トã•れã¦ã¾ã›ã‚“ã€?
249             *
250             * @return 更新キー(é…å?)
251             */
252            @Override
253            public String[] getKeys() {
254                    String errMsg = "ã“ã?クラスã§ã¯ã€ã‚µãƒã?トã•れã¦ã¾ã›ã‚“ã€?;
255                    throw new RuntimeException( errMsg );
256            }
257    
258            /**
259             * (ã“ã?クラスã§ã¯ã€ã‚µãƒã?トã•れã¦ã¾ã›ã‚“ã€?
260             *
261             * @param keys 更新キー(é…å?)
262             */
263            @Override
264            public void setKeys( final String[] keys ) {
265                    String errMsg = "ã“ã?クラスã§ã¯ã€ã‚µãƒã?トã•れã¦ã¾ã›ã‚“ã€?;
266                    throw new RuntimeException( errMsg );
267            }
268    
269            /**
270             * ローカルã®èª­å–対象をã?リモート接続å?ã®èª­å–対象ã¨ãƒªãƒ¢ãƒ¼ãƒˆæŽ¥ç¶šå?URLã«åˆ?§£ã—ã¾ã™ã?
271             *
272             * @param localReadObj ローカルã®èª­å–対象
273             */
274            protected abstract void splitReadObj( final String localReadObj );
275    
276            /**
277             * リモート接続å?URLã‚’è¿”ã—ã¾ã™ã?
278             * ã“ã?メソãƒ?ƒ‰ã¯ã€{@link #splitReadObj(String)}ã®å¾Œã«å‘¼ã³å‡ºã—ã™ã‚‹å¿?¦ãŒã‚りã¾ã™ã?
279             *
280             * @return リモート接続å?URL
281             */
282            protected abstract String getRemoteHost();
283    
284            /**
285             * リモート接続å?ã®èª­å–対象を返ã—ã¾ã™ã?
286             * ã“ã?メソãƒ?ƒ‰ã¯ã€{@link #splitReadObj(String)}ã®å¾Œã«å‘¼ã³å‡ºã—ã™ã‚‹å¿?¦ãŒã‚りã¾ã™ã?
287             *
288             * @return 接続URL
289             */
290            protected abstract String getRemoteReadObj();
291    
292            /**
293             * æŒ?®šã?URLã«æŽ¥ç¶šã—ã¾ã™ã?
294             *
295             * @param url 接続URL
296             * @param postData POSTã™ã‚‹ãƒ??ã‚¿
297             * @param config ä¼é?設定オブジェクãƒ?
298             *
299             * @return 接続オブジェク�
300             */
301            protected URLConnect connect( final String url, final String postData, final TransferConfig config ) throws IOException {
302                    URLConnect conn = new URLConnect( url, TransferConfig.HTTP_AUTH_USER_PASS );
303                    if( config.getProxyHost() != null && config.getProxyHost().length() > 0  ) {
304                            conn.setProxy( config.getProxyHost(),config.getProxyPort() );
305                    }
306                    conn.setCharset( "UTF-8" );
307                    conn.setPostData( postData );
308                    conn.connect();
309                    return conn;
310            }
311    
312            /**
313             * æŒ?®šã?URLã«æŽ¥ç¶šã—レスãƒãƒ³ã‚¹ãƒ??ã‚¿ã‚’è¿”ã—ã¾ã™ã?
314             *
315             * @param conn URL接続オブジェク�
316             *
317             * @return レスãƒãƒ³ã‚¹ãƒ??ã‚¿
318             */
319            private String readData( final URLConnect conn ) throws IOException {
320                    String readData = conn.readData();
321                    // è¿”ã•れãŸãƒ??タ中ã«"row_error"ãŒå­˜åœ¨ã™ã‚‹å ´åˆã?エラーã¨ã—ã¦å‡¦ç?—ã¾ã™ã?
322                    if( readData != null && readData.indexOf( "row_error" ) >= 0 ) {
323                            throw new RuntimeException( readData );
324                    }
325                    return readData;
326            }
327    
328            /**
329             * ä¼é?設定オブジェクトをURLパラメーターã«å¤‰æ›ã—ã¾ã™ã?
330             *
331             * @param       keys    更新キー(é…å?)
332             * @param       config  ä¼é?設定オブジェクãƒ?
333             *
334             * @return      URLパラメーター
335             */
336            protected String getPostData( final String[] keys, final TransferConfig config ) {
337                    // サブクラスåã‹ã‚‰è¦ªã‚¯ãƒ©ã‚¹å?"_"を除ã?Ÿéƒ¨åˆ?‚’èª­å–æ–¹æ³•ã¨ã™ã‚‹ã€?
338                    String kbRead = getClass().getName().replace( getClass().getSuperclass().getName() + "_", "" );
339    
340                    StringBuilder buf = new StringBuilder();
341                    buf.append( "KBREAD="           ).append( StringUtil.urlEncode( kbRead ) );
342                    buf.append( "&READOBJ="             ).append( StringUtil.urlEncode( getRemoteReadObj() ) );
343                    buf.append( "&READPRM="             ).append( StringUtil.urlEncode( config.getReadPrm() ) );
344                    buf.append( "&KBEXEC="              ).append( StringUtil.urlEncode( config.getKbExec() ) );
345                    buf.append( "&EXECDBID="    ).append( StringUtil.urlEncode( config.getExecDbid() )  );
346                    buf.append( "&EXECOBJ="             ).append( StringUtil.urlEncode( config.getExecObj() ) );
347                    buf.append( "&EXECPRM="             ).append( StringUtil.urlEncode( config.getExecPrm() ) );
348                    buf.append( "&ERROR_SENDTO=").append( StringUtil.urlEncode( config.getErrorSendto() ) );
349                    buf.append( "&HFROM="               ).append( StringUtil.urlEncode( config.getHfrom() ) );
350    
351                    if( keys != null && keys.length > 0 ) {
352                            buf.append( "&n=" ).append( keys.length );
353                            for( int i=0; i<keys.length; i++ ) {
354                                    buf.append( "&k" ).append( i ).append( "=" );
355                                    buf.append( StringUtil.urlEncode( keys[i] ) );
356                            }
357                    }
358                    else {
359                            buf.append( "&n=0" );
360                    }
361    
362                    return buf.toString();
363            }
364    }