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.util;
017
018import java.io.BufferedInputStream;
019import java.io.BufferedReader;
020import java.io.File;
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.InputStreamReader;
024import java.io.OutputStream;
025import java.io.PrintStream;
026import java.io.PrintWriter;
027import java.io.UnsupportedEncodingException;
028import java.net.HttpURLConnection;
029import java.net.InetSocketAddress;
030import java.net.Proxy;
031import java.net.SocketAddress;
032import java.net.URL;
033import java.net.URLConnection;
034
035import org.apache.commons.codec.binary.Base64;
036
037/**
038 * URLConnect は、指定のURL にアクセスして、情報/データを取得します。
039 * URL へのアクセスにより、エンジンでは各種処理を実行させることが可能になります。
040 * 例えば、帳票デーモンの起動や、長時間かかる処理の実行などです。
041 * なお、URLに引数が付く場合は、ダブルコーテーションで括って下さい。
042 * - 付き引数は、指定順番は、関係ありません。- 無し引数(url,user:passwd)は、
043 * 順番があります。
044 *
045 * Usage: java org.opengion.fukurou.util.URLConnect [-info/-data] … url [user:passwd]
046 *
047 *   args[*] : [-info/-data]       情報の取得か、データの取得かを指定します(初期値:-data)。
048 *   args[*] : [-post=ファイル名]  POSTメソッドを指定して、ファイルデータを送信します(初期値:-get)。
049 *   args[*] : [-encode=UTF-8]     エンコードを指定します(通常は接続先のencodeを使用)。
050 *   args[*] : [-out=ファイル名]   結果を指定されたファイルエンコードでファイルに出力します。
051 *   args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)。
052 *   args[A] : url                 URLを指定します。GETの場合、パラメータは ?KEY=VALです。
053 *   args[B] : [user:passwd]       BASIC認証のエリアへのアクセス時に指定します。
054 *
055 * ※ プロキシ設定の3つの方法
056 * プロキシ設定には、3つの方法があります。
057 *   1.
058 *     URL url = URL( "http",proxyHost,proxyPort, url );
059 *     URLConnection urlConn = url.openConnection();
060 *   2.
061 *     SocketAddress scaddr = new InetSocketAddress( proxyHost, proxyPort );
062 *     Proxy proxy = new Proxy( Proxy.Type.HTTP, scaddr );
063 *     URL url = new Url( url );
064 *     URLConnection urlConn = url.openConnection( proxy );
065 *   3.
066 *     System.setProperty( "http.proxyHost",host );
067 *     System.setProperty( "http.proxyPort",String.valueOf( port ) );
068 *     URL url = new Url( url );
069 *     URLConnection urlConn = url.openConnection();
070 *     System.clearProperty( "http.proxyHost" );
071 *     System.clearProperty( "http.proxyPort" );
072 *
073 * 1. 、2. の方法は、urlConn.getContentType() を実行すると、エラーになります。(原因不明)
074 * 3. の方法では、マルチスレッドで実行する場合に、問題が発生します。
075 * 本クラスでは、方法2 を使用しています。
076 *
077 * @version  4.0
078 * @author   Kazuhiko Hasegawa
079 * @since    JDK5.0,
080 */
081public class URLConnect {
082        private static final String CR = System.getProperty("line.separator");
083
084        private final String urlStr ;
085        private final String userPass ;
086
087        private int                             rpsCode         = -1;
088        private String                  rpsMethod       = null;
089        private String                  rpsMessage      = null;
090        private String                  type            = null;
091        private String                  charset         = null;
092        private String                  postData        = null;
093        private long                    length          = -1;
094        private long                    date            = -1;
095        private long                    modified        = -1;
096        private boolean                 isPost          = false;
097        private URLConnection   conn            = null;
098        private Proxy                   proxy           = Proxy.NO_PROXY;
099
100        /**
101         * コンストラクター
102         *
103         * @param       url     接続するアドレスを指定します。(http://server:port/dir/file.html)
104         * @param       pass    ユーザー:パスワード(認証接続が必要な場合)
105         */
106        public URLConnect( final String url, final String pass ) {
107                urlStr = url;
108                userPass = pass;
109        }
110
111        /**
112         * 指定のURLに対して、コネクトするのに使用するプロキシ設定を行います。
113         * このときに、ヘッダー情報を内部変数に設定しておきます。
114         *
115         * @param       host    接続するプロキシのホスト名
116         * @param       port    接続するプロキシのポート番号
117         */
118        public void setProxy( final String host,final int port ) {
119                // 方法2.
120                SocketAddress scaddr = new InetSocketAddress( host, port );
121                proxy = new Proxy( Proxy.Type.HTTP, scaddr );
122        }
123
124        /**
125         * 指定のURLに対して、コネクトします。
126         * このときに、ヘッダー情報を内部変数に設定しておきます。
127         *
128         * @og.rev 4.0.1.0 (2007/12/12) Postで複数キーを使えるように修正
129         * @og.rev 5.1.6.0 (2010/05/01) charsetを指定できるようにする
130         * @throws  IOException 入出力エラーが発生したとき
131         */
132        public void connect() throws IOException {
133                conn = getConnection();
134
135                if( isPost ) {
136                        conn.setDoOutput( true );                       // POST可能にする
137
138                        OutputStream os = null;                         // POST用のOutputStream
139                        PrintStream  ps = null;
140                        try {
141                                os = conn.getOutputStream();    // POST用のOutputStreamを取得
142                                // 5.1.6.0 (2010/05/01)
143                                if( charset != null ) {
144                                        ps = new PrintStream( os, false, charset );
145                                }
146                                else {
147                                        ps = new PrintStream( os );
148                                }
149                                ps.print( postData );                   // 4.1.0.0 (2007/12/22)
150                        }
151                        finally {
152                                Closer.ioClose( ps );           // close 処理時の IOException を無視
153                                Closer.ioClose( os );           // close 処理時の IOException を無視
154                        }
155                }
156                else {
157                        // GET 時のコネクション接続
158                        conn.connect();
159                }
160
161                setInfo( conn );
162        }
163
164        /**
165         * U接続先のデータを取得します。
166         *
167         * この処理の前に、connect() 処理を実行しておく必要があります。
168         * 取得したデータは、指定のURL へのアクセスのみです。
169         * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、
170         * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。
171         * このメソッドでの処理では、それらのファイル内に指定されているURLの
172         * 再帰的な取得は行いません。
173         * よって、フレーム処理なども行いません。
174         * 本来は、Stream のまま処理することで、バイナリデータも扱えますが、ここでは、
175         * テキストデータ(String)に変換して使用できるデータのみ扱えます。
176         *
177         * @return      接続結果
178         * @throws  IOException 入出力エラーが発生したとき
179         */
180        public String readData() throws IOException {
181                if( conn == null ) {
182                        String errMsg = "connect() されていません。データ取得前にconnect()してください。";
183                        throw new RuntimeException( errMsg );
184                }
185
186                BufferedReader reader = null;
187                StringBuilder buf = new StringBuilder();
188                try {
189                        reader = getReader();
190
191                        String line ;
192                        while( (line = reader.readLine()) != null ) {
193                                buf.append( line ).append( CR );
194                        }
195                }
196                catch( UnsupportedEncodingException ex ) {
197                        String errMsg = "指定された文字エンコーディングがサポートされていません。" + CR
198                                                + " url=[" + urlStr + "]"
199                                                + " charset=[" + charset + "]" ;
200                        throw new RuntimeException( errMsg,ex );
201                }
202                finally {
203                        Closer.ioClose( reader );
204                        disconnect();
205                }
206
207                return buf.toString();
208        }
209
210        /**
211         * サーバへのほかの要求が今後発生しそうにないことを示します。
212         *
213         */
214        public void disconnect() {
215                if( conn instanceof HttpURLConnection ) {
216                        ((HttpURLConnection)conn).disconnect() ;
217                }
218        }
219
220        /**
221         * URL と ユーザー:パスワードを与えて、URLConnectionを返します。
222         *
223         * ユーザー:パスワード が null でない場合は、BASCI認証エリアへのアクセスの為、
224         * BASE64Encoder を行って、Authorization プロパティーを設定します。
225         * ここで返す URLConnection は、すでに、connect() メソッド実行済みの
226         * リモート接続が完了した状態のオブジェクトです。
227         *
228         * @return  URLConnectionオブジェクト
229         * @throws  IOException 入出力エラーが発生したとき
230         */
231        // 5.1.5.0 (2010/04/01) SOAP対応により、PROTECTED化
232        protected URLConnection getConnection() throws IOException {
233                final URL url = new URL( urlStr );
234
235                // 方法2.
236                URLConnection urlConn = url.openConnection( proxy );
237
238                if( userPass != null ) {
239                        byte[] encoded = Base64.encodeBase64( userPass.getBytes( StringUtil.DEFAULT_CHARSET ) );        // 5.5.2.6 (2012/05/25) findbugs対応
240                        String userPassEnc = new String( encoded,StringUtil.DEFAULT_CHARSET );          // 5.5.2.6 (2012/05/25) findbugs対応
241                        urlConn.setRequestProperty( "Authorization","Basic " + userPassEnc );
242                }
243
244                return urlConn ;
245        }
246
247        /**
248         * 接続先の情報を内部変数に設定します。
249         *
250         * ここでは、タイプ,エンコード,レスポンスコード,レスポンスメッセージ を設定します。
251         * レスポンスコード,レスポンスメッセージは、接続コネクションが、HttpURLConnection の
252         * 場合のみセットされます。
253         * 途中でエラーが発生した場合でも、継続処理できるようにします。これは、プロキシ
254         * 設定の方法により、conn.getContentType()  でエラーが発生する場合があるためです。
255         *
256         * @og.rev 5.5.9.1 (2012/12/07) charsetは、null の場合のみ設定します。
257         *
258         * @param   conn 接続先のコネクション
259         */
260        private void setInfo( final URLConnection conn ) {
261                try {
262                        // 5.5.9.1 (2012/12/07) charsetは、null の場合のみ設定します。
263                        if( charset == null ) { charset = conn.getContentEncoding(); }
264                        type    = conn.getContentType() ;
265                        length  = conn.getContentLength();
266                        date    = conn.getDate();
267                        modified= conn.getLastModified();
268
269                        if( charset == null && type != null ) {
270                                int adrs = type.indexOf( "charset" );
271                                int adrs2 = type.indexOf( '=',adrs );
272                                if( adrs > 0 && adrs2 > adrs ) {
273                                        charset = type.substring( adrs2+1 ).trim();
274                                }
275                        }
276
277                        if( conn instanceof HttpURLConnection ) {
278                                HttpURLConnection httpConn = (HttpURLConnection) conn;
279                                rpsCode         = httpConn.getResponseCode();
280                                rpsMethod       = httpConn.getRequestMethod();
281                                rpsMessage      = httpConn.getResponseMessage() + code2Message( rpsCode );
282                        }
283                }
284                // 4.0.0.0 (2007/11/29) Exception から、IOException と RuntimeException に変更
285                catch( IOException ex ) {
286                        System.out.println( ex.getMessage() );
287                }
288                catch( RuntimeException ex ) {
289                        System.out.println( ex.getMessage() );
290                }
291        }
292
293        /**
294         * URL 情報を取得します。
295         *
296         * @og.rev 4.3.4.4 (2009/01/01) メソッド名変更
297         *
298         * @return      URL情報
299         */
300        public String getUrl() { return urlStr; }
301
302        /**
303         * POSTするデータを設定します。
304         *
305         * POSTする場合は、connect() 処理を行う前に、データを設定しておく必要があります。
306         *
307         * @og.rev 4.1.0.0 (2007/12/22) キーと値のセットを取得するよう変更
308         * @param       data    POSTデータ
309         */
310        public void setPostData( final String data ) {
311                postData = data;
312                if( postData != null && "?".indexOf( postData ) == 0 ) { // 先頭の?を抜く
313                        postData = postData.substring(1);
314                }
315                if( postData != null ) { isPost = true; }
316        }
317
318        /**
319         * タイプ 情報を取得します。
320         *
321         * @return      タイプ 情報
322         */
323        public String getType() { return type; }
324
325        /**
326         * データ量 情報を取得します。
327         *
328         * @return      データ量 情報
329         */
330        public long getLength() { return length; }
331
332        /**
333         * 作成日時 情報を取得します。
334         *
335         * @return      作成日時
336         */
337        public long getDate() { return date; }
338
339        /**
340         * 更新日時 情報を取得します。
341         *
342         * @return      更新日時
343         */
344        public long getModified() { return modified; }
345
346        /**
347         * 結果コード 情報(HttpURLConnection)を取得します。
348         *
349         * @return      結果コード 情報
350         */
351        public int getCode() { return rpsCode; }
352
353        /**
354         * メソッド 情報(HttpURLConnection)を取得します。
355         *
356         * @return      メソッド 情報
357         */
358        public String getMethod() { return rpsMethod; }
359
360        /**
361         * メッセージ 情報(HttpURLConnection)を取得します。
362         *
363         * @return      メッセージ 情報
364         */
365        public String getMessage() { return rpsMessage; }
366
367        /**
368         * キャラクタ 情報を取得します。
369         *
370         * @return      キャラクタ 情報
371         */
372        public String getCharset() { return charset; }
373
374        /**
375         * キャラクタ 情報を設定します。
376         *
377         * @param  chset キャラクタ 情報
378         */
379        public void setCharset( final String chset ) { charset = chset; }
380
381        /**
382         * 接続先のデータのリーダーを取得します。
383         *
384         * この処理の前に、connect() 処理を実行しておく必要があります。
385         * 取得したデータは、指定のURL へのアクセスのみです。
386         * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、
387         * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。
388         * このメソッドでの処理では、それらのファイル内に指定されているURLの
389         * 再帰的な取得は行いません。
390         * よって、フレーム処理なども行いません。
391         *
392         * @return      接続結果のリーダー
393         * @throws  IOException 入出力エラーが発生したとき
394         */
395        public BufferedReader getReader() throws IOException {
396                InputStream in = conn.getInputStream();
397
398                final BufferedReader reader ;
399                if( charset != null ) {
400                        reader = new BufferedReader( new InputStreamReader( in,charset ) );
401                }
402                else {
403                        reader = new BufferedReader( new InputStreamReader( in,StringUtil.DEFAULT_CHARSET ) );          // 5.5.2.6 (2012/05/25) findbugs対応
404                }
405
406                return reader;
407        }
408
409        /**
410         * 接続先のデータの入力ストリームを取得します。
411         *
412         * この処理の前に、connect() 処理を実行しておく必要があります。
413         * 取得したデータは、指定のURL へのアクセスのみです。
414         * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、
415         * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。
416         * このメソッドでの処理では、それらのファイル内に指定されているURLの
417         * 再帰的な取得は行いません。
418         * よって、フレーム処理なども行いません。
419         *
420         * @og.rev 5.4.2.0 (2011/12/01) 新規追加
421         *
422         * @return      接続結果の入力を出力します。
423         * @throws  IOException 入出力エラーが発生したとき
424         */
425        public InputStream getInputStream() throws IOException {
426                return new BufferedInputStream( conn.getInputStream() );                // 5.5.2.4 (2012/05/16)
427        }
428
429        /**
430         * HttpURLConnection のレスポンスコードに対応するメッセージ文字列を返します。
431         *
432         * HttpURLConnection の getResponseCode() メソッドにより取得された、HTTPレスポンスコード
433         * に対応する文字列を返します。この文字列は、HttpURLConnection で定義された
434         * static 定数のコメントを、定義しています。
435         *
436         * @og.rev 5.6.7.0 (2013/07/27) レスポンスコード例 追加
437         *
438         * @param       code    HTTPレスポンスコード
439         *
440         * @return      レスポンスコードに対応する文字列
441         * @see HttpURLConnection#HTTP_ACCEPTED
442         */
443        public static String code2Message( final int code ) {
444                final String msg ;
445                switch( code ) {
446                        case 100                                                                                : msg = "100: 要求は続行可能です。"                                               ;       break;  // 5.6.7.0 (2013/07/27)
447                        case 101                                                                                : msg = "101: プロトコルを切り替えます。"                            ;       break;  // 5.6.7.0 (2013/07/27)
448                        case HttpURLConnection.HTTP_OK                                  : msg = "200: OK です。"                                                           ;       break;
449                        case HttpURLConnection.HTTP_CREATED                     : msg = "201: 作成されました。"                                                 ;       break;
450                        case HttpURLConnection.HTTP_ACCEPTED                    : msg = "202: 許可されました。"                                                 ;       break;
451                        case HttpURLConnection.HTTP_NOT_AUTHORITATIVE   : msg = "203: 不当な情報です。"                                                 ;       break;
452                        case HttpURLConnection.HTTP_NO_CONTENT                  : msg = "204: コンテンツがありません。"                                     ;       break;
453                        case HttpURLConnection.HTTP_RESET                               : msg = "205: コンテンツをリセットします。"                           ;       break;
454                        case HttpURLConnection.HTTP_PARTIAL                     : msg = "206: 部分的なコンテンツです。"                                     ;       break;
455                        case HttpURLConnection.HTTP_MULT_CHOICE                 : msg = "300: 複数選択されています。"                                      ;       break;
456                        case HttpURLConnection.HTTP_MOVED_PERM                  : msg = "301: 永続的に移動されました。"                                     ;       break;
457                        case HttpURLConnection.HTTP_MOVED_TEMP                  : msg = "302: 一時的に切り替えます。"                                      ;       break;
458                        case HttpURLConnection.HTTP_SEE_OTHER                   : msg = "303: 他を参照してください。"                                      ;       break;
459                        case HttpURLConnection.HTTP_NOT_MODIFIED                : msg = "304: 修正されませんでした。"                                      ;       break;
460                        case HttpURLConnection.HTTP_USE_PROXY                   : msg = "305: プロキシを使用してください。"                           ;       break;
461                        case 306                                                                                : msg = "306: 仕様の拡張案です。"                                                ;       break;  // 5.6.7.0 (2013/07/27)
462                        case 307                                                                                : msg = "307: 一時的なリダイレクトです。"                            ;       break;  // 5.6.7.0 (2013/07/27)
463                        case HttpURLConnection.HTTP_BAD_REQUEST                 : msg = "400: 不当な要求です。"                                                 ;       break;
464                        case HttpURLConnection.HTTP_UNAUTHORIZED                : msg = "401: 認証されませんでした。"                                      ;       break;
465                        case HttpURLConnection.HTTP_PAYMENT_REQUIRED    : msg = "402: 支払いが必要です。"                                                ;       break;
466                        case HttpURLConnection.HTTP_FORBIDDEN                   : msg = "403: 禁止されています。"                                                ;       break;
467                        case HttpURLConnection.HTTP_NOT_FOUND                   : msg = "404: 見つかりませんでした。"                                      ;       break;
468                        case HttpURLConnection.HTTP_BAD_METHOD                  : msg = "405: メソッドは許可されません。"                            ;       break;
469                        case HttpURLConnection.HTTP_NOT_ACCEPTABLE              : msg = "406: 許容されません。"                                                 ;       break;
470                        case HttpURLConnection.HTTP_PROXY_AUTH                  : msg = "407: プロキシの認証が必要です。"                            ;       break;
471                        case HttpURLConnection.HTTP_CLIENT_TIMEOUT              : msg = "408: 要求が時間切れです。"                                               ;       break;
472                        case HttpURLConnection.HTTP_CONFLICT                    : msg = "409: 重複しています。"                                                 ;       break;
473                        case HttpURLConnection.HTTP_GONE                                : msg = "410: 存在しません。"                                                  ;       break;
474                        case HttpURLConnection.HTTP_LENGTH_REQUIRED     : msg = "411: 長さが必要です。"                                                 ;       break;
475                        case HttpURLConnection.HTTP_PRECON_FAILED               : msg = "412: 前提条件が正しくありません。"                           ;       break;
476                        case HttpURLConnection.HTTP_ENTITY_TOO_LARGE    : msg = "413: 要求エンティティが長すぎます。"                  ;       break;
477                        case HttpURLConnection.HTTP_REQ_TOO_LONG                : msg = "414: 要求 URL が長すぎます。"                                   ;       break;
478                        case HttpURLConnection.HTTP_UNSUPPORTED_TYPE    : msg = "415: サポートされないメディアタイプです。"               ;       break;
479                        case 416                                                                                : msg = "416: 要求された範囲は不十分です。"                           ;       break;  // 5.6.7.0 (2013/07/27)
480                        case 417                                                                                : msg = "417: 要求どおりの処理が不可能です。"                  ;       break;  // 5.6.7.0 (2013/07/27)
481                        case HttpURLConnection.HTTP_INTERNAL_ERROR              : msg = "500: 内部サーバエラーです。"                                      ;       break;
482                        case HttpURLConnection.HTTP_NOT_IMPLEMENTED     : msg = "501: 実装されていません。"                                               ;       break;
483                        case HttpURLConnection.HTTP_BAD_GATEWAY                 : msg = "502: 誤ったゲートウェイです。"                                     ;       break;
484                        case HttpURLConnection.HTTP_UNAVAILABLE                 : msg = "503: サービスが利用できません。"                            ;       break;
485                        case HttpURLConnection.HTTP_GATEWAY_TIMEOUT     : msg = "504: ゲートウェイが時間切れです。"                           ;       break;
486                        case HttpURLConnection.HTTP_VERSION                     : msg = "505: HTTP バージョンがサポートされていません。"; break;
487                        default : msg = code + ": 未定義" ;                // 5.6.7.0 (2013/07/27)
488                }
489                return msg ;
490        }
491
492        /**
493         * サンプル実行用のメインメソッド
494         *
495         * Usage: java org.opengion.fukurou.util.URLConnect [-info/-data] … url [user:passwd]
496         *
497         *   args[*] : [-info/-data]       情報の取得か、データの取得かを指定します(初期値:-data)。
498         *   args[*] : [-post=ファイル名]  POSTメソッドを指定して、ファイルデータを送信します(初期値:-get)。
499         *   args[*] : [-encode=UTF-8]     エンコードを指定します(通常は接続先のencodeを使用)
500         *   args[*] : [-out=ファイル名]   結果をファイルに出力します。ファイルエンコードも指定します。
501         *   args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)。
502         *   args[A] : url                 URLを指定します。GETの場合、パラメータは ?KEY=VALです。
503         *   args[B] : [user:passwd]       BASIC認証のエリアへのアクセス時に指定します。
504         *
505         * @og.rev 5.6.7.0 (2013/07/27) -errEx 追加
506         *
507         * @param       args    コマンド引数配列
508         * @throws IOException 入出力エラーが発生したとき
509         */
510        public static void main( final String[] args ) throws IOException {
511                if( args.length < 3 ) {
512                        LogWriter.log( "Usage: java org.opengion.fukurou.util.URLConnect [-info/-data] … url [user:passwd]"                             );
513                        LogWriter.log( "   args[*] : [-info/-data]       情報の取得か、データの取得かを指定します(初期値:-data)"                       );
514                        LogWriter.log( "   args[*] : [-post=ファイル名]  POSTメソッドを指定して、ファイルデータを送信します(初期値:-get)"      );
515                        LogWriter.log( "   args[*] : [-encode=UTF-8]     エンコードを指定します。(通常は接続先のencodeを使用)"                                );
516                        LogWriter.log( "   args[*] : [-out=ファイル名]   結果をファイルに出力します。ファイルエンコードも指定します"              );
517                        LogWriter.log( "   args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)" );
518                        LogWriter.log( "   args[A] : url                 URLを指定します。GETの場合、パラメータは ?KEY=VALです"                    );
519                        LogWriter.log( "   args[B] : [user:passwd]       BASIC認証のエリアへのアクセス時に指定します"                                              );
520                        return;
521                }
522
523                boolean isInfo  = false ;
524                boolean isPost  = false ;
525                String postKey  = null ;
526                String postFile = null ;
527                String encode   = null ;
528                String outFile  = null ;
529                boolean isEx    = false ;                               // 5.6.7.0 (2013/07/27) 追加
530                String[] vals   = new String[2];                // url,userPass の順に引数設定
531
532                int adrs = 0;
533                for( int i=0; i<args.length; i++ ) {
534                        String arg = args[i];
535                        if( arg.equalsIgnoreCase( "-info" ) ) {
536                                isInfo = true;
537                        }
538                        else if( arg.equalsIgnoreCase( "-data" ) ) {
539                                isInfo = false;
540                        }
541                        else if( arg.startsWith( "-post=" ) ) {
542                                isPost = true;
543                                int sepAdrs = arg.indexOf( ':',6 );
544                                postKey  = arg.substring( 6,sepAdrs );
545                                postFile = arg.substring( sepAdrs+1 );
546                        }
547                        else if( arg.startsWith( "-encode=" ) ) {
548                                encode = arg.substring( 8 );
549                        }
550                        else if( arg.startsWith( "-out=" ) ) {
551                                outFile = arg.substring( 5 );
552                        }
553                        else if( arg.startsWith( "-errEx=" ) ) {                                                        // 5.6.7.0 (2013/07/27) 追加
554                                isEx = "true".equalsIgnoreCase( arg.substring( 7 ) );
555                        }
556                        else if( arg.startsWith( "-" ) ) {
557                                System.out.println( "Error Argment:" + arg );
558                        }
559                        else {
560                                vals[adrs++] = arg;
561                        }
562                }
563
564                String urlStr   = vals[0] ;
565                String userPass = vals[1] ;
566
567                URLConnect conn = new URLConnect( urlStr,userPass );
568
569                // POST データは、connect() する前に、設定します。
570                if( isPost ) {
571                        FileString file = new FileString();
572                        file.setFilename( postFile );
573                        String postData = file.getValue();
574
575                        conn.setPostData( XHTMLTag.urlEncode(postKey, postData) );
576                }
577
578                conn.connect();
579                if( encode != null ) {
580                        conn.setCharset( encode );              // encode 指定
581                }
582                else {
583                        encode = conn.getCharset();             // 指定がなければ、接続先の charset を使用
584                }
585
586                final PrintWriter writer ;
587                if( outFile != null ) {
588                        writer = FileUtil.getPrintWriter( new File( outFile ),encode );
589                }
590                else {
591                        writer = FileUtil.getLogWriter( "System.out" );
592                }
593
594                int code = conn.getCode();              // 5.6.7.0 (2013/07/27) レスポンスコードは、常に拾っておきます。
595                if( isInfo ) {
596                        writer.println( "URL    :" + conn.getUrl() );
597                        writer.println( "Type   :" + conn.getType() );
598                        writer.println( "Code   :" + code );                                    // 5.6.7.0 (2013/07/27) 取得済みの値を利用。
599                        writer.println( "Message:" + conn.getMessage() );
600                        writer.println( "Charset:" + conn.getCharset() );
601                }
602                else {
603                        writer.println( conn.readData() );
604                }
605
606                conn.disconnect();
607
608                Closer.ioClose( writer );
609
610                // 5.6.7.0 (2013/07/27) trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます
611                if( isEx && code >= 400 ) {
612                        String errMsg = URLConnect.code2Message( code );
613                        throw new RuntimeException( errMsg );
614                }
615        }
616}