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