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