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