    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.File;
    019import java.io.IOException;
    020import java.io.PrintWriter;
    021import java.net.HttpURLConnection;
    022import java.net.MalformedURLException;
    023import java.net.URL;
    024import java.util.Arrays;
    025import java.util.ArrayList;
    026import java.util.List;
    027import java.nio.file.Files;
    028import java.nio.file.Paths;
    029        // import java.nio.charset.Charset;
    030import java.nio.charset.StandardCharsets;
    031import java.util.concurrent.TimeUnit;                                                                                   // 8.0.0.0 (2021/07/31) Add
    032
    033// 8.0.0.0 (2021/07/31) httpclient-4.5.5.jar → httpclient5-5.1.jar
    034// org.apache.http → org.apache.hc.core5.http or org.apache.hc.client5.http
    035import org.apache.hc.core5.http.Header;
    036import org.apache.hc.core5.http.HttpEntity;
    037import org.apache.hc.core5.http.HttpHost;
    038import org.apache.hc.core5.http.ClassicHttpRequest;
    039import org.apache.hc.core5.http.ContentType;
    040import org.apache.hc.core5.http.NameValuePair;
    041// import org.apache.hc.core5.http.ParseException;                                                              // 8.0.0.0 (2021/07/31) Add
    042import org.apache.hc.core5.http.HttpException;                                                                  // 8.4.0.0 (2022/12/23) Add
    043import org.apache.hc.core5.http.ClassicHttpResponse;                                                    // 8.4.0.0 (2022/12/23) Add
    044// import org.apache.hc.core5.http.HttpStatus;                                                                  // 8.4.0.0 (2022/12/23) Add
    045import org.apache.hc.core5.http.io.entity.EntityUtils;
    046import org.apache.hc.core5.http.io.entity.StringEntity;
    047import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
    048import org.apache.hc.core5.http.io.HttpClientResponseHandler;                                   // 8.4.0.0 (2022/12/23) Add
    049import org.apache.hc.core5.http.message.BasicHeader;
    050import org.apache.hc.core5.http.message.BasicNameValuePair;
    051// import org.apache.hc.core5.http.message.StatusLine;                                                  // 8.0.0.0 (2021/07/31) Delete
    052import org.apache.hc.client5.http.auth.AuthScope;
    053import org.apache.hc.client5.http.auth.Credentials;
    054import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
    055import org.apache.hc.client5.http.config.RequestConfig;
    056// import org.apache.http.client.config.CookieSpecs;                                                    // 8.0.0.0 (2021/07/31) Delete
    057// import org.apache.hc.client5.http.auth.CredentialsProvider;                                  // 8.0.0.0 (2021/07/31) Delete
    058import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
    059import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
    060// import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;                             // 8.0.0.0 (2021/07/31) Delete
    061import org.apache.hc.client5.http.classic.methods.HttpGet;
    062import org.apache.hc.client5.http.classic.methods.HttpPost;
    063//import org.apache.http.client.methods.HttpUriRequest;                                                 // 8.0.0.0 (2021/07/31)
    064import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
    065import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
    066import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
    067// import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
    068// import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;                             // 8.0.0.0 (2021/08/31)
    069// import org.apache.hc.client5.http.cookie.Cookie;                                                             // 8.0.0.0 (2021/08/31)
    070// import org.apache.hc.client5.http.impl.classic.HttpClients;
    071// import org.apache.hc.client5.http.cookie.CookieStore;
    072// import org.apache.http.impl.client.DefaultHttpClient;;
    073import org.apache.hc.client5.http.cookie.BasicCookieStore;
    074// import org.apache.hc.client5.http.cookie.Cookie;
    075import org.apache.hc.client5.http.protocol.HttpClientContext;
    076// import java.io.UnsupportedEncodingException;                                                                 // 8.0.0.0 (2021/07/31) Delete
    077// import org.apache.hc.client5.http.ClientProtocolException;                                   // 8.4.0.0 (2022/12/23) Add
    078
    079import java.net.URI;
    080import java.net.URISyntaxException;
    081// import java.util.Calendar;                                                                                                   // 8.0.0.0 (2021/08/31)
    082import java.util.Map;
    083// import java.util.Map.Entry;
    084import java.util.HashMap;
    085
    086// import org.apache.http.impl.client.DefaultRedirectStrategy;
    087// import org.apache.http.HttpRequest;
    088// import org.apache.http.HttpResponse;
    089// import org.apache.http.protocol.HttpContext;
    090// import org.apache.http.ProtocolException;
    091// import org.apache.http.impl.client.LaxRedirectStrategy;                                              // 8.0.0.0 (2021/07/31) Delete
    092
    093// import org.opengion.fukurou.system.Closer;
    094import org.opengion.fukurou.system.LogWriter;
    095import org.opengion.fukurou.system.OgRuntimeException ;
    096
    097import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;
    098import static org.opengion.fukurou.system.HybsConst.CR;
    099
    100/**
    101 * HttpConnect は、指定のURL にアクセスして、データを取得します。
    102 * URL へのアクセスにより、エンジンでは各種処理を実行させることが可能になります。
    103 * 例えば、帳票デーモンの起動や、長時間かかる処理の実行などです。
    104 * なお、URLに引数が付く場合は、ダブルコーテーションで括って下さい。
    105 * URL の指定は、先頭に何もつけませ。指定の順番も関係ありません。
    106 * - 付き引数は、指定順番は、関係ありません。
    107 * 先頭が # の引数は、コメントと判断します。
    108 *
    109 * <pre>
    110 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd]
    111 *   args[A] : url                     ＵＲＬを指定します。GETの場合、パラメータは ?KEY=VALです
    112 *   args[*] : [-param=key:value]      POST/GET時のﾊﾟﾗﾒｰﾀのｷｰと値を:で区切って指定します。(複数回指定可)
    113 *   args[*] : [-header=key:value]     ﾍｯﾀﾞｰに設定するﾊﾟﾗﾒｰﾀのｷｰと値を:で区切って指定します。(複数回指定可)
    114 *   args[*] : [-auth=user:pass]       BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します
    115 *   args[*] : [-proxy=host:port]      proxy を使用する場合のホストとポートを指定します。
    116 *   args[*] : [-timeout=3]            接続タイムアウト時間を(秒)で指定します(初期値:無指定)
    117 *   args[*] : [-encode=UTF-8]         エンコードを指定します。(初期値は UTF-8)
    118 *   args[*] : [-out=ファイル名]       結果をファイルに出力します。初期値は標準出力です
    119 *   args[*] : [-download=ファイル名]  ﾌｧｲﾙ名を指定して、ﾀﾞｳﾝﾛｰﾄﾞします
    120 *   args[*] : [-upload=ファイル名]    ﾌｧｲﾙ名を指定して、multipart/form-dataでﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞします
    121 *   args[*] : [-postRedirect=true]    POST時に強制的にﾘﾀﾞｲﾚｸﾄを行います(GET時は自動でﾘﾀﾞｲﾚｸﾄします)(初期値:false) 7.2.5.0 (2020/06/01)
    122 *   args[*] : [-usePost=true]         POSTを強制的に使用する場合にｾｯﾄします(初期値:false)
    123 *   args[*] : [-errEx=true/false]     trueの場合、ﾚｽﾎﾟﾝｽｺｰﾄﾞが、4XX,5XX の時に RuntimeException を投げます(初期値:false)
    124 *   args[*] : [-authJson=JSONコード]  JSONコードで認証する場合に使用します。8.0.0.0 (2021/08/31)
    125 *   args[*] : [-authURL=認証用URL]    JSONコードで認証するURLを指定します。8.0.0.0 (2021/08/31)
    126 *   args[*] : [-reqJson=JSONコード]   パラメータをJSONで指定する場合に使用します。8.0.0.0 (2021/08/31)
    127 *   args[*] : [#････]                 ｺﾒﾝﾄ引数。(BATﾌｧｲﾙ上に残しておきたいが、使用したくない場合など)
    128 *   args[*] : [-debug=true/false]     trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)
    129 * </pre>
    130 *
    131 * ※ URLConnect との違い。
    132 *    -info/-data 等の区別の廃止。(実質、-info がなくなる。)
    133 *    setDownloadFile(String) 追加(-binaryの代用)
    134 *    setUploadFile(String) 追加
    135 *    proxy 設定の変更
    136 *
    137 * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    138 * @og.rev 8.0.0.0 (2021/08/31) httpclient5 対応
    139 *
    140 * https://hc.apache.org/httpcomponents-core-5.1.x/current/httpcore5/apidocs/
    141 * https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/
    142 *
    143 * @version  8.0.0.0
    144 * @author   Kazuhiko Hasegawa
    145 * @since    JDK11.0,
    146 */
    147public class HttpConnect {
    148        /** エンコードの初期値  {@value} */
    149        public static final String DEFAULT_CHARSET = "UTF-8" ;
    150        /** 言語の初期値  {@value} */
    151        public static final String DEFAULT_LANG = "ja-JP" ;
    152        /** User-Agentの初期値  {@value} */
    153        public static final String DEFAULT_AGENT = "openGion with Apache HttpClient" ;
    154        /** GETで指定するときのURLの長さ制限  {@value}  (IEの場合は、2,083文字) */
    155        public static final int MAX_GET_LENGTH = 2000 ;
    156
    157        private final String urlStr ;
    158        private final String user ;
    159        private final String pass ;
    160
    161        private final Map<String,String> jsonMap = new  HashMap<>();
    162
    163        private int                     rpsCode         = -1;
    164        private String          rpsMessage      ;
    165        private String          charset         = DEFAULT_CHARSET ;
    166        private String          upldFile        ;
    167        private String          dwldFile        ;                               // ﾊﾞｲﾅﾘﾌｧｲﾙとして受け取る場合のファイル名
    168        private int                     timeout         = -1;
    169        private boolean         isPost          ;
    170        private boolean         postRedirect;                           // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)
    171        private boolean         isDebug         ;
    172
    173        private String          authJson        ;                               // -authJson            // 8.0.0.0 (2021/08/31)
    174        private String          authURL         ;                               // -authURL                     // 8.0.0.0 (2021/08/31)
    175        private String          reqJson         ;                               // -reqJson                     // 8.0.0.0 (2021/08/31)
    176
    177        private HttpHost        proxy           ;
    178
    179        // 初期ﾍｯﾀﾞｰ情報
    180        private static final List<Header> INIT_HEADER =
    181                                                        Arrays.asList(
    182                                                                new BasicHeader( "Accept-Charset"       , DEFAULT_CHARSET ) ,
    183                                                                new BasicHeader( "Accept-Language"      , DEFAULT_LANG  ) ,
    184                                                                new BasicHeader( "User-Agent"           , DEFAULT_AGENT )
    185                                                        );
    186
    187        private final List<NameValuePair>       reqParamList = new ArrayList<NameValuePair>();  // ﾘｸｴｽﾄﾊﾟﾗﾒｰﾀｰ(主にPOST時)
    188        private final List<Header>                      headers          = new ArrayList<>( INIT_HEADER );      // ﾍｯﾀﾞｰﾊﾟﾗﾒｰﾀｰ
    189
    190        // GET でのﾊﾟﾗﾒｰﾀのマージ。きちんとした方法がわかるまでの暫定処置
    191        private final StringBuilder                     reqParamBuf  = new StringBuilder( BUFFER_MIDDLE );
    192
    193        /**
    194         * 接続先URLと、認証用ユーザー:パスワードを指定する、コンストラクター
    195         *
    196         * 認証が必要ない場合は、userPass は、null でかまいません。
    197         * 接続先URLは、HttpConnect で、urlEncode しますので、そのままの文字列でかまいません。
    198         *
    199         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    200         * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応
    201         *
    202         * @param       url                     接続するアドレスを指定します。(http://server:port/dir/file.html)
    203         * @param       userPass        ユーザー：パスワード(認証接続が必要な場合)
    204         */
    205        public HttpConnect( final String url, final String userPass ) {
    206                urlStr = StringUtil.urlEncode2( url );
    207
    208                if( StringUtil.isNull( userPass ) ) {
    209                        user = null;
    210                        pass = null;
    211                }
    212                else {
    213                        final String[] prm = StringUtil.csv2Array( userPass , ':' , 2 );
    214                        user = prm[0];
    215                        pass = prm[1];
    216                }
    217        }
    218
    219//      /**
    220//       * Form認証でのログイン
    221//       *
    222//       * https://hc.apache.org/httpcomponents-client-5.1.x/examples.html
    223//       * https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientFormLogin.java
    224//       *
    225//       * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応
    226//       */
    227//      private String formLogin() {
    228//              String body = null;
    229//              String secCheckURL = null;
    230//
    231//              final BasicCookieStore cookieStore = new BasicCookieStore();
    232//              try (final CloseableHttpClient httpclient = HttpClients.custom()
    233//                              .setDefaultCookieStore(cookieStore)
    234//                              .build()) {
    235////                    final HttpGet httpget = new HttpGet(urlStr);
    236//                      final URI uri = new URI(urlStr);                                        // j_security_check のアドレスを取るために。
    237//                      final HttpGet httpget = new HttpGet(uri);
    238//
    239//                      try (final CloseableHttpResponse response1 = httpclient.execute(httpget)) {
    240//                              final HttpEntity entity = response1.getEntity();
    241//
    242//                              System.out.println("Login form get: " + response1.getCode() + " " + response1.getReasonPhrase());
    243//                              final String loginBody = EntityUtils.toString( entity, charset );
    244//                              // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。
    245//                              final int ed = loginBody.indexOf( "j_security_check" );
    246//                              if( ed >= 0 ) {
    247//                                      final int st = loginBody.lastIndexOf( '"',ed );         // 逆順に探す。
    248//                                      if( st >= 0 ) {
    249//                                              secCheckURL = uri.getScheme() + "://" + uri.getHost() + ':' + uri.getPort()
    250//                                                                                      + loginBody.substring( st+1,ed ) + "j_security_check" ;
    251//                                              System.out.println(secCheckURL);
    252//                                      }
    253//                              }
    254//
    255//                              EntityUtils.consume(entity);            // リソースを解放
    256//
    257//      //                      System.out.println("Initial set of cookies:");
    258//      //                      final List<Cookie> cookies = cookieStore.getCookies();
    259//      //                      if (cookies.isEmpty()) {
    260//      //                              System.out.println("None");
    261//      //                      } else {
    262//      //                              for (int i = 0; i < cookies.size(); i++) {
    263//      //                                      System.out.println("- " + cookies.get(i));
    264//      //                              }
    265//      //                      }
    266//                      }
    267//
    268//                      final ClassicHttpRequest login = ClassicRequestBuilder.post()
    269//      //                              .setUri(new URI("http://localhost:8828/gf/jsp/j_security_check"))
    270//                                      .setUri(new URI( secCheckURL ))
    271//                                      .addParameter("j_username", user)
    272//                                      .addParameter("j_password", pass)
    273//                                      .addParameter("j_security_check", "login")
    274//                                      .build();
    275//                      try (final CloseableHttpResponse response2 = httpclient.execute(login)) {
    276//                              final HttpEntity entity = response2.getEntity();
    277//
    278//                              System.out.println("Login form get: " + response2.getCode() + " " + response2.getReasonPhrase());
    279//                              body = EntityUtils.toString( entity, charset );
    280//
    281//                              EntityUtils.consume(entity);            // リソースを解放
    282//
    283//      //                      System.out.println("Post logon cookies:");
    284//      //                      final List<Cookie> cookies = cookieStore.getCookies();
    285//      //                      if (cookies.isEmpty()) {
    286//      //                              System.out.println("None");
    287//      //                      } else {
    288//      //                              for (int i = 0; i < cookies.size(); i++) {
    289//      //                                      System.out.println("- " + cookies.get(i));
    290//      //                              }
    291//      //                      }
    292//                      }
    293//              }
    294//              catch( IOException ex ) { ex.printStackTrace(); }
    295//              catch( URISyntaxException ex ) { ex.printStackTrace(); }
    296//              catch( final ParseException ex ) {ex.printStackTrace();}
    297//
    298//              return body ;
    299//      }
    300
    301        /**
    302         * Form認証でのログイン
    303         *
    304         * https://hc.apache.org/httpcomponents-client-5.2.x/examples.html
    305         * https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientFormLogin.java
    306         *
    307         * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応
    308         * @og.rev 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    309         */
    310        private String formLogin( final CloseableHttpClient client , final URI uri ) {
    311                String body = null;
    312
    313                try {
    314                        final URI secCheckURI = uri.resolve( "j_security_check" );
    315                        if( isDebug ) { System.out.println( "security URI=" + secCheckURI ); }
    316
    317                        final ClassicHttpRequest login = ClassicRequestBuilder.post()
    318        //                              .setUri(new URI("http://localhost:8828/gf/jsp/j_security_check"))
    319                                        .setUri( secCheckURI )
    320                                        .addParameter("j_username", user)
    321                                        .addParameter("j_password", pass)
    322                                        .addParameter("j_security_check", "login")
    323                                        .build();
    324
    325                        // 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    326                        // https://www.cnblogs.com/liyuanhong/p/16007750.html
    327                        // Create a custom response handler
    328                        final HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>() {
    329                                @Override
    330                                public String handleResponse( final ClassicHttpResponse response) throws IOException,HttpException {
    331                                        final HttpEntity entity = response.getEntity();
    332
    333                                        rpsCode         = response.getCode();                                                                   // 8.0.0.0 (2021/07/31)
    334                                        rpsMessage      = code2Message( rpsCode ).trim();                                               // 8.0.0.0 (2021/07/31)
    335
    336                                        // Form認証の場合、バイナリ処理は、formLogin 内で行います。
    337                                        // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。
    338                                        final String rtnBody ;
    339                                        if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) {
    340                                                Files.write( Paths.get( dwldFile ) , EntityUtils.toByteArray( entity ) );
    341                                                rtnBody = dwldFile;
    342                                        }
    343                                        else {
    344                                                rtnBody = EntityUtils.toString( entity, charset );
    345                                        }
    346                                        EntityUtils.consume(entity);            // リソースを解放
    347                                        return rtnBody ;
    348                                }
    349                        };
    350                        body = client.execute(login, responseHandler);
    351
    352//                      try( CloseableHttpResponse response = client.execute(login) ) {
    353//                              final HttpEntity entity = response.getEntity();
    354//
    355//                              rpsCode    = response.getCode();                                                                        // 8.0.0.0 (2021/07/31)
    356//                              rpsMessage = code2Message( rpsCode ).trim();                                            // 8.0.0.0 (2021/07/31)
    357//
    358//                              // Form認証の場合、バイナリ処理は、formLogin 内で行います。
    359//                              // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。
    360//                              if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) {
    361//                                      Files.write( Paths.get( dwldFile ) , EntityUtils.toByteArray( entity ) );
    362//                                      body = dwldFile;
    363//                              }
    364//                              else {
    365//                                      body = EntityUtils.toString( entity, charset );
    366//                              }
    367//                              EntityUtils.consume(entity);            // リソースを解放
    368//                      }
    369                }
    370//              catch( final IOException | ParseException ex ) {
    371                catch( final IOException ex ) {
    372                        throw new OgRuntimeException( ex );
    373                }
    374
    375                return body ;
    376        }
    377
    378        /**
    379         * 特別版ログイン
    380         *
    381         * @og.rev 8.0.0.0 (2021/08/31) httpclient4 → httpclient5 対応
    382         * @og.rev 8.0.2.0 (2021/11/30) PMD:Avoid instantiating new objects inside loops
    383         * @og.rev 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    384         */
    385        private String jsonLogin( final CloseableHttpClient client ) {
    386                String body = null;
    387
    388                try {
    389                        final ClassicHttpRequest login = new HttpPost( authURL );
    390
    391                        // 8.0.0.0 (2021/08/31)
    392                        login.setHeader("Content-type", "application/json");
    393                        final HttpEntity stringEntity = new StringEntity(authJson,ContentType.APPLICATION_JSON);
    394                        login.setEntity( stringEntity );
    395
    396                        // 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    397                        // https://www.cnblogs.com/liyuanhong/p/16007750.html
    398                        // Create a custom response handler
    399                        final HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>() {
    400                                @Override
    401                                public String handleResponse( final ClassicHttpResponse response) throws IOException,HttpException {
    402                                        final HttpEntity entity = response.getEntity();
    403
    404                                        rpsCode         = response.getCode();                                                                   // 8.0.0.0 (2021/07/31)
    405                                        rpsMessage      = code2Message( rpsCode ).trim();                                               // 8.0.0.0 (2021/07/31)
    406                                        if( isDebug ) { System.out.println( "jsonLogin=" + rpsCode ); }
    407
    408                                        final String rtnBody = EntityUtils.toString( entity, charset );
    409                                        if( isDebug ) { System.out.println( "Login=" + rtnBody ); }
    410
    411                                        // ログイン時のリターンJSONから、ﾊﾟﾗﾒｰﾀを取得するMapを作成します。
    412                                        if( !jsonMap.isEmpty() ) {
    413                                                final StringBuilder buf = new StringBuilder();          // 8.0.2.0 (2021/11/30)
    414                                                for( final String key : jsonMap.keySet() ) {
    415                                                        final int st = rtnBody.indexOf( key );
    416                                                        if( st >= 0 ) {
    417                                                                final int ed = rtnBody.indexOf( ',',st+key.length() );
    418                                                                buf.setLength(0);                                                       // 8.0.2.0 (2021/11/30) StringBuilder の初期化
    419                                                                if( ed > 0 ) {
    420                                                                        for( int i=st+key.length(); i<ed; i++ ) {
    421                                                                                final char ch = rtnBody.charAt(i);
    422                                                                                if( ch != '"' && ch != ':' && ch != ' ' ) {
    423                                                                                        buf.append( ch );
    424                                                                                }
    425                                                                        }
    426                                                                }
    427                                                                jsonMap.put( key,buf.toString() );
    428                                                                if( isDebug ) { System.out.println( "Map=" +  key + ":" + buf.toString() ); }
    429                                                        }
    430                                                }
    431                                        }
    432
    433                                        EntityUtils.consume(entity);            // リソースを解放
    434                                        return rtnBody ;
    435                                }
    436                        };
    437                        body = client.execute(login, responseHandler);
    438
    439//                      try( CloseableHttpResponse response = client.execute(login) ) {
    440//                              final HttpEntity entity = response.getEntity();
    441//
    442//                              rpsCode    = response.getCode();                                                                        // 8.0.0.0 (2021/07/31)
    443//                              rpsMessage = code2Message( rpsCode ).trim();                                            // 8.0.0.0 (2021/07/31)
    444//                              if( isDebug ) { System.out.println( "jsonLogin=" + rpsCode ); }
    445//
    446//                              body = EntityUtils.toString( entity, charset );
    447//
    448//                              if( isDebug ) { System.out.println( "Login=" + body ); }
    449//
    450//                              // ログイン時のリターンJSONから、ﾊﾟﾗﾒｰﾀを取得するMapを作成します。
    451//                              if( !jsonMap.isEmpty() ) {
    452//                                      final StringBuilder buf = new StringBuilder();          // 8.0.2.0 (2021/11/30)
    453//                                      for( final String key : jsonMap.keySet() ) {
    454//                                              final int st = body.indexOf( key );
    455//                                              if( st >= 0 ) {
    456//                                                      final int ed = body.indexOf( ',',st+key.length() );
    457////                                                    final StringBuilder buf = new StringBuilder();
    458//                                                      buf.setLength(0);                                                       // 8.0.2.0 (2021/11/30) StringBuilder の初期化
    459//                                                      if( ed > 0 ) {
    460//                                                              for( int i=st+key.length(); i<ed; i++ ) {
    461//                                                                      final char ch = body.charAt(i);
    462//                                                                      if( ch != '"' && ch != ':' && ch != ' ' ) {
    463//                                                                              buf.append( ch );
    464//                                                                      }
    465//                                                              }
    466//                                                      }
    467//                                                      jsonMap.put( key,buf.toString() );
    468//                                                      if( isDebug ) { System.out.println( "Map=" +  key + ":" + buf.toString() ); }
    469//                                              }
    470//                                      }
    471//                              }
    472//
    473//                              EntityUtils.consume(entity);            // リソースを解放
    474//                      }
    475                }
    476//              catch( final IOException | ParseException ex ) {
    477                catch( final IOException ex ) {
    478                        throw new OgRuntimeException( ex );
    479                }
    480
    481                return body ;
    482        }
    483
    484        /**
    485         * 特別版ログイン
    486         *
    487         * @og.rev 8.0.0.0 (2021/08/31) httpclient4 → httpclient5 対応
    488         * @og.rev 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    489         */
    490        private String jsonDataget( final CloseableHttpClient client , final URI uri ) {
    491                String body = null;
    492
    493                try {
    494                        final ClassicHttpRequest httpReq ;
    495
    496                        if( reqJson == null ) {
    497                                httpReq = new HttpGet( uri );   // public/html/reportMain.html の時
    498                        }
    499                        else {
    500                                httpReq = new HttpPost( uri );
    501                                httpReq.setHeader("Content-type", "application/json");
    502
    503                                String tempJson = reqJson;
    504                                if( !jsonMap.isEmpty() ) {
    505                                        for( final Map.Entry<String,String> entry : jsonMap.entrySet() ) {
    506                                                tempJson = tempJson.replace( '$'+entry.getKey()+'$' , entry.getValue() );
    507                                        }
    508                                }
    509
    510                                if( isDebug ) { System.out.println( "reqJson=" + tempJson ); }
    511
    512                                final HttpEntity stringEntity = new StringEntity(tempJson,ContentType.APPLICATION_JSON);
    513                                httpReq.setEntity( stringEntity );
    514                        }
    515
    516                        // 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    517                        final HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>() {
    518                                @Override
    519                                public String handleResponse( final ClassicHttpResponse response) throws IOException,HttpException {
    520                                        final HttpEntity entity = response.getEntity();
    521
    522                                        rpsCode         = response.getCode();                                                                   // 8.0.0.0 (2021/07/31)
    523                                        rpsMessage      = code2Message( rpsCode ).trim();                                               // 8.0.0.0 (2021/07/31)
    524                                        if( isDebug ) { System.out.println( "jsonDataget=" + rpsCode ); }
    525
    526                                        final String rtnBody = EntityUtils.toString( entity, charset );
    527                                        EntityUtils.consume(entity);            // リソースを解放
    528                                        return rtnBody ;
    529                                }
    530                        };
    531                        body = client.execute(httpReq, responseHandler);
    532
    533//                      try( CloseableHttpResponse response = client.execute(httpReq) ) {
    534//                              final HttpEntity entity = response.getEntity();
    535//
    536//                              rpsCode    = response.getCode();                                                                        // 8.0.0.0 (2021/07/31)
    537//                              rpsMessage = code2Message( rpsCode ).trim();                                            // 8.0.0.0 (2021/07/31)
    538//                              if( isDebug ) { System.out.println( "jsonDataget=" + rpsCode ); }
    539//
    540//                              body = EntityUtils.toString( entity, charset );
    541//                              EntityUtils.consume(entity);            // リソースを解放
    542//                      }
    543                }
    544//              catch( final IOException | ParseException ex ) {
    545                catch( final IOException ex ) {
    546                        throw new OgRuntimeException( ex );
    547                }
    548
    549                return body ;
    550        }
    551
    552        /**
    553         * URL接続先のデータを取得します。
    554         *
    555         * この処理の前に、必要な情報を設定して置いてください。
    556         * また、code や message は、このメソッドを実行しないと取得できませんのでご注意ください。
    557         *
    558         * 取得したデータは、指定のURL へのアクセスのみです。
    559         * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、
    560         * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。
    561         * このメソッドでの処理では、それらのファイル内に指定されているURLの
    562         * 再帰的な取得は行いません。
    563         * よって、フレーム処理なども行いません。
    564         *
    565         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    566         * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応
    567         * @og.rev 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    568         *
    569         * @return      接続結果
    570         * @og.rtnNotNull
    571         * @throws  IOException 入出力エラーが発生したとき
    572         * @throws  MalformedURLException URLの形式が間違っている場合
    573         */
    574        public String readData() throws IOException , MalformedURLException {
    575                final ClassicHttpRequest method ;                                                                                               // 8.0.0.0 (2021/07/31)
    576                if( isPost ) {
    577                        if( isDebug ) { System.out.println( "POST URL=" + urlStr ); }
    578                        method = new HttpPost( urlStr );
    579
    580                        if( !reqParamList.isEmpty() ) {
    581                                method.setEntity( new UrlEncodedFormEntity( reqParamList ) );                                           // 8.0.0.0 (2021/07/31)
    582                                if( isDebug ) { reqParamList.forEach( v -> System.out.println( "PARAM KEY=" + v.getName() + " , VAL=" + v.getValue() ) ); }
    583                        }
    584
    585                        if( !StringUtil.isNull( upldFile ) ) {
    586                                final File file = new File( upldFile );
    587                                if( isDebug ) { System.out.println( "  MULTI FILE=" + file ); }
    588                                final HttpEntity entity = MultipartEntityBuilder.create()
    589                                                                                .setCharset( StandardCharsets.UTF_8 )   // ﾌｧｲﾙ名の文字化け対策
    590                                                                                .addBinaryBody( "upload" ,
    591                                                                                                                file ,
    592                                                                                                                ContentType.DEFAULT_BINARY ,
    593                                                                                                                file.getName() )
    594                                                                                .build();
    595                                method.setEntity( entity );
    596                        }
    597                }
    598                else {
    599                        // GET でのﾊﾟﾗﾒｰﾀのマージ。きちんとした方法がわかるまでの暫定処置
    600                        final String getStr = reqParamBuf.length() == 0
    601                                                                        ? urlStr
    602                                                                        : reqParamBuf.toString() ;
    603
    604                        if( isDebug ) { System.out.println( "GET URL=" + getStr ); }
    605
    606                        method = new HttpGet( getStr );
    607                }
    608
    609                final HttpClientContext context = HttpClientContext.create();
    610//              if( ckStore != null ) {                                 // 8.0.0.0 (2021/07/31) 未使用
    611//                      context.setCookieStore(ckStore);
    612//              }
    613
    614                String body = null;
    615                try( CloseableHttpClient client = getClient() ) {
    616                        // 8.4.0.0 (2022/12/23) CloseableHttpClientのexecute(ClassicHttpRequest)は推奨されません
    617                        // https://www.cnblogs.com/liyuanhong/p/16007750.html
    618                        // Create a custom response handler
    619                        final HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>() {
    620                                @Override
    621                                public String handleResponse( final ClassicHttpResponse response) throws IOException,HttpException {
    622                                        final HttpEntity entity = response.getEntity();
    623
    624                                        rpsCode         = response.getCode();                                                                   // 8.0.0.0 (2021/07/31)
    625                                        if( isDebug ) { System.out.println( "readData=" + rpsCode ); }
    626                                        rpsMessage      = code2Message( rpsCode ).trim();                                               // 8.0.0.0 (2021/07/31)
    627
    628                                        String rtnBody = null;
    629                                        if( entity == null ) {
    630                                                rtnBody = rpsMessage;                   // HttpEntity が受け取れなかった場合は、メッセージを表示します。
    631                                        }
    632                                        else {
    633                                                // body は一度しか処理できない。EntityUtils.toByteArray( entity ) か、EntityUtils.toString( entity, charset );
    634                                                try {
    635                                                        final URI uri = method.getUri();
    636
    637                                                        // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。
    638                                                        if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) {
    639                                                                final byte[] dwnBody = EntityUtils.toByteArray( entity );
    640                                                                final String text = new String( dwnBody,charset );
    641
    642                                                                // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。
    643                                                                if( text.contains( "j_security_check" ) ) {
    644                                                                        rtnBody = formLogin( client,uri );              // Form認証時の再接続処理
    645                                                                }
    646                                                                else {
    647                                                                        Files.write( Paths.get( dwldFile ) , dwnBody );
    648                                                                        rtnBody = dwldFile;
    649                                                                }
    650                                                        }
    651                                                        else {
    652                                                                // form認証チェックが必要なので、バイナリでも文字列で受け取る。
    653                                                                rtnBody = EntityUtils.toString( entity, charset );
    654                                                                // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。
    655                                                                if( rtnBody.contains( "j_security_check" ) ) {
    656                                                                        rtnBody = formLogin( client,uri );              // Form認証時の再接続処理
    657                                                                }
    658                                                                else if( authJson != null ) {                           // 8.0.0.0 (2021/08/31)
    659                                                                        rtnBody = jsonLogin( client );                  // 認証時の再接続処理
    660                                                                        rtnBody = jsonDataget( client,uri );    // 認証後の再接続処理
    661                                                                }
    662                                                        }
    663                                                }
    664                                                catch( final URISyntaxException ex ) {
    665                                                        throw new OgRuntimeException( ex );
    666                                                }
    667                                        }
    668                                        EntityUtils.consume(entity);                    // リソースを解放
    669                                        return rtnBody ;
    670                                }
    671                        };
    672                        body = client.execute(method,context,responseHandler);
    673                }
    674
    675//              try( CloseableHttpClient client = getClient() ;
    676//                       CloseableHttpResponse response = client.execute(method,context) ) {
    677//
    678//                      rpsCode    = response.getCode();                                                                        // 8.0.0.0 (2021/07/31)
    679//                      if( isDebug ) { System.out.println( "readData=" + rpsCode ); }
    680//                      rpsMessage = code2Message( rpsCode ).trim();                                            // 8.0.0.0 (2021/07/31)
    681//
    682//                      final HttpEntity entity = response.getEntity();
    683//
    684//                      if( entity == null ) {
    685//                              body = rpsMessage;                      // HttpEntity が受け取れなかった場合は、メッセージを表示します。
    686//                      }
    687//                      else {
    688//                              // body は一度しか処理できない。EntityUtils.toByteArray( entity ) か、EntityUtils.toString( entity, charset );
    689//
    690//                              final URI uri = method.getUri();
    691//
    692//                              // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。
    693//                              if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) {
    694//                                      final byte[] dwnBody = EntityUtils.toByteArray( entity );
    695//                                      final String text = new String( dwnBody,charset );
    696//
    697//                                      // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。
    698//                                      if( text.contains( "j_security_check" ) ) {
    699//                                              body = formLogin( client,uri );         // Form認証時の再接続処理
    700//                                      }
    701//                                      else {
    702//                                              Files.write( Paths.get( dwldFile ) , dwnBody );
    703//                                              body = dwldFile;
    704//                                      }
    705//                              }
    706//                              else {
    707//                                      // form認証チェックが必要なので、バイナリでも文字列で受け取る。
    708//                                      body = EntityUtils.toString( entity, charset );
    709//                                      // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。
    710//                                      if( body.contains( "j_security_check" ) ) {
    711//                                              body = formLogin( client,uri );         // Form認証時の再接続処理
    712//                                      }
    713//                                      else if( authJson != null ) {                           // 8.0.0.0 (2021/08/31)
    714//                                              body = jsonLogin( client );                     // 認証時の再接続処理
    715//                                              body = jsonDataget( client,uri );       // 認証後の再接続処理
    716//                                      }
    717//                              }
    718//                      }
    719//                      EntityUtils.consume(entity);                    // リソースを解放
    720//              }
    721                // 8.0.0.0 (2021/07/31) Add
    722//              catch( final ParseException | URISyntaxException ex ) {
    723                catch( final IOException ex ) {
    724                        throw new OgRuntimeException( ex );
    725                }
    726
    727                return body;
    728        }
    729
    730        /**
    731         * 接続先の HttpClient オブジェクトを作成します。
    732         *
    733         * 接続に必要な情報を、設定します。
    734         * CloseableHttpClient は、AutoCloseable を継承しています。
    735         *
    736         * 7.2.5.0 (2020/06/01)
    737         *   通常、HttpClientはGETの場合は自動でﾘﾀﾞｲﾚｸﾄ処理しますが、
    738         *   POSTの場合は、302が返るだけでﾘﾀﾞｲﾚｸﾄ処理しません。
    739         *   http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3[HTTP RFC 2616]で規定されています。
    740         *   ここでは、ﾀﾞｳﾝﾛｰﾄﾞﾌｧｲﾙがあり、POSTの場合だけ強制的に
    741         *
    742         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    743         * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)
    744         * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応
    745         * @og.rev 8.4.0.0 (2022/12/23) BuilderのsetConnectTimeout(long,TimeUnit)は推奨されません
    746         *
    747         * @return  HttpConnectionオブジェクト
    748         * @throws  IOException 入出力エラーが発生したとき
    749         */
    750        private CloseableHttpClient getClient() throws MalformedURLException {
    751                final HttpClientBuilder clBuild = HttpClientBuilder.create();
    752
    753                final BasicCookieStore cookieStore = new BasicCookieStore();
    754                clBuild.setDefaultCookieStore(cookieStore) ;
    755
    756                if( timeout >= 0 ) {
    757                        final RequestConfig.Builder reqConfig = RequestConfig.custom();
    758        //              reqConfig.setConnectTimeout( timeout ,TimeUnit.SECONDS );                               // 8.0.0.0 (2021/07/31) timeoutの単位は(秒)
    759                        reqConfig.setConnectionRequestTimeout( timeout ,TimeUnit.SECONDS );             // 8.4.0.0 (2022/12/23) メソッド変更
    760
    761                        clBuild.setDefaultRequestConfig( reqConfig.build() );
    762                }
    763
    764                // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)
    765                // 8.0.0.0 (2021/07/31) httpclient5-5.1対応により LaxRedirectStrategy 廃止の為一旦削除
    766        //      if( postRedirect ) {
    767        //              clBuild.setRedirectStrategy( new LaxRedirectStrategy() );
    768        //      }
    769
    770                // headers (初期設定も入っているので、通常は、empty にはならない。)
    771                if( !headers.isEmpty() ) {
    772                        clBuild.setDefaultHeaders( headers );
    773                }
    774
    775                // Proxy
    776                if( proxy != null ) {
    777                        clBuild.setProxy( proxy );
    778                }
    779
    780                // Auth
    781                // https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java
    782                if( !StringUtil.isNull( user ) ) {
    783                        final URL url = new URL( urlStr );
    784                        final AuthScope   scope = new AuthScope( url.getHost(), url.getPort() );
    785                        final Credentials cred  = new UsernamePasswordCredentials( user ,pass.toCharArray() );  // 8.0.0.0 (2021/07/31)
    786
    787                        final BasicCredentialsProvider credProvider = new BasicCredentialsProvider();                   // 8.0.0.0 (2021/07/31)
    788                        credProvider.setCredentials( scope,cred );
    789                        clBuild.setDefaultCredentialsProvider( credProvider );
    790                }
    791
    792        //      // (デフォルトのHttpClientは、最新のRFC準拠ヘッダーを理解するのが困難です。)
    793        //  // RequestConfig に、CookieSpecs.STANDARD を設定しているが、効果なければ、使わなくしてしまう。
    794        //      clBuild.disableCookieManagement();
    795
    796                return clBuild.build();         // HttpClient httpClient  = HttpClientBuilder.create().*****.build();
    797        }
    798
    799        /**
    800         * 接続先に使用する引数(ﾊﾟﾗﾒｰﾀ)を追加します。
    801         *
    802         * これは、POSTでも、GETでも使用できます。
    803         * POSTの場合は、NameValuePair として、HttpPost に、Entity としてセットするデータを設定します。
    804         * GET の場合は、既存の接続先URLに、&amp;ｷｰ=値････ で、追記します。
    805         * すでに、ﾊﾟﾗﾒｰﾀが指定済みの場合は、&amp; で、そうでなければ、? で連結します。
    806         * ここで指定するﾊﾟﾗﾒｰﾀは、内部で、urlEncode しますので、そのままの文字列でかまいません。
    807         *
    808         * ﾃﾞﾌｫﾙﾄは、GETですが、Internet Explorer では URL に最大 2,083 文字しか指定できないため、
    809         * それ以上の場合は、POST に自動で切り替えます。
    810         *
    811         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    812         *
    813         * @param       key     パラメータキー(nullの場合は、登録しません)
    814         * @param       val     パラメータ値
    815         */
    816        public void addRequestProperty( final String key, final String val ) {
    817                if( !StringUtil.isNull( key ) ) {
    818                        reqParamList.add( new BasicNameValuePair( key,val ) );                          // POST のときのﾊﾟﾗﾒｰﾀ。(GETでも使えるはず？)
    819
    820                        if( !isPost ) {                                                                                                         // 明らかに、GET でない場合は、この処理を行わない。
    821                                if( reqParamBuf.length() == 0 ) {                                                               // 初めての場合
    822                                        reqParamBuf.append( urlStr )
    823                                                                .append( urlStr.indexOf( '?' ) > 0 ? '&' : '?' )
    824                                                                .append( StringUtil.urlEncode2( key ) )
    825                                                                .append( '=' )
    826                                                                .append( StringUtil.urlEncode2( val ) );                // null のときは、長さゼロ文字列になる。
    827                                }
    828                                else if( reqParamBuf.length() > MAX_GET_LENGTH ) {
    829                                        if( isDebug ) { System.out.println( "GET → POST変更： URLの長さ制限＜" + reqParamBuf.length() ); }
    830                                        isPost = true;                                                                                          // GETで送れるURLの長さ制限を超えた場合は、POSTにする。
    831                                }
    832                                else {
    833                                        reqParamBuf.append( '&' )
    834                                                                .append( StringUtil.urlEncode2( key ) )
    835                                                                .append( '=' )
    836                                                                .append( StringUtil.urlEncode2( val ) );                // null のときは、長さゼロ文字列になる。
    837                                }
    838                        }
    839                }
    840        }
    841
    842        /**
    843         * setRequestPropertyでセットするデータを設定します。
    844         *
    845         * keys,vals各々、カンマ区切りで分解します。
    846         *
    847         * @og.rev 5.10.16.0 (2019/10/04) 追加
    848         *
    849         * @param       keys    パラメータキー（カンマ区切り）
    850         * @param       vals    パラメータ（カンマ区切り）
    851         */
    852        public void setRequestProperty( final String keys, final String vals ) {
    853                if( keys != null && keys.length() > 0 && vals != null && vals.length() > 0 ){
    854                        final String[]  propKeys = StringUtil.csv2Array( keys );
    855                        final String[]  propVals = StringUtil.csv2Array( vals );
    856
    857                        if( propKeys.length == propVals.length && propKeys.length > 0 ) {
    858                                for( int i=0; i<propKeys.length; i++ ) {
    859                                        addRequestProperty( propKeys[i], propVals[i] );
    860                                }
    861                        }
    862                        else {
    863                                final String errMsg = "パラメータのキーと、値の数が一致しません。"   + CR
    864                                                        + " key=[" + keys + "]"                                                                 + CR
    865                                                        + " val=[" + vals + "]" ;
    866                                throw new IllegalArgumentException( errMsg );
    867                        }
    868                }
    869        }
    870
    871        /**
    872         * 指定のURLに対して、コネクトするのに使用するプロキシ設定を行います。
    873         * このときに、ヘッダー情報を内部変数に設定しておきます。
    874         *
    875         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    876         *
    877         * @param       host    接続するプロキシのホスト名(nullの場合は、登録しません)
    878         * @param       port    接続するプロキシのポート番号
    879         */
    880        public void setProxy( final String host,final int port ) {
    881                if( !StringUtil.isNull( host ) ) {
    882                        proxy = new HttpHost( host , port );
    883                }
    884        }
    885
    886        /**
    887         * Header として、HttpClient にセットするデータを設定します。
    888         *
    889         * 例えばJSON形式でPOSTする場合は通常"Content-Type", "application/json"を指定します。
    890         *
    891         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    892         *
    893         * @param       key     パラメータキー(nullの場合は、登録しません)
    894         * @param       val     パラメータ値(nullの場合は、登録しません)
    895         */
    896        public void addHeaderProperty( final String key, final String val ) {
    897                if( !StringUtil.isNull( key ) && !StringUtil.isNull( val ) ) {
    898                        headers.add( new BasicHeader( key,val ) );
    899                }
    900        }
    901
    902        /**
    903         * URL接続先のバイナリファイルをダウンロード取得します。
    904         *
    905         * 取得したファイルは、dwldFile にバイナリのまま書き込まれます。
    906         * よって、エンコードの指定は不要です。
    907         *
    908         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    909         *
    910         * @param       dwldFile ﾀﾞｳﾝﾛｰﾄﾞするファイル名。
    911         * @throws  IOException 入出力エラーが発生したとき
    912         */
    913        public void setDownloadFile( final String dwldFile ) throws IOException {
    914                this.dwldFile = dwldFile;
    915        }
    916
    917        /**
    918         * URL接続先のバイナリファイルをアップロードします。
    919         *
    920         * 取得したファイルは、upldFile にバイナリのまま書き込まれます。
    921         * よって、エンコードの指定は不要です。
    922         * アップロード は、multipart/form-data で送信するため、isPost = true を
    923         * 内部的に設定しておきます。
    924         *
    925         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    926         * @og.rev 7.2.5.0 (2020/06/01) upldFileのnull判定を入れます。
    927         *
    928         * @param       upldFile ｱｯﾌﾟﾛｰﾄﾞするファイル名。
    929         * @throws  IOException 入出力エラーが発生したとき
    930         */
    931        public void setUploadFile( final String upldFile ) throws IOException {
    932                if( upldFile != null ) {
    933                        this.upldFile = upldFile;
    934                        isPost = true;
    935                }
    936        }
    937
    938        /**
    939         * エンコード情報を設定します。
    940         *
    941         * 初期値は、UTF-8 です。
    942         *
    943         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    944         *
    945         * @param  chset エンコード情報(nullの場合は、初期値:UTF-8 になります)
    946         */
    947        public void setCharset( final String chset ) {
    948                if( !StringUtil.isNull( chset ) ) {
    949                        charset = chset;
    950                }
    951        }
    952
    953        /**
    954         * 接続タイムアウト時間を(秒)で指定します
    955         *
    956         * 実際には、org.apache.http.client.config.RequestConfig に対して、
    957         *       .setConnectTimeout( timeout * 1000 )
    958         *       .setSocketTimeout(  timeout * 1000 )
    959         * のように、 1000倍して設定しています。
    960         * 0 は、無限のタイムアウト、マイナスは、設定しません。(つまりJavaの初期値のまま)
    961         *
    962         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    963         *
    964         * @param       tout    タイムアウト時間(秒) (ゼロは、無制限)
    965         */
    966        public void setTimeout( final int tout ) {
    967                timeout = tout;
    968        }
    969
    970        /**
    971         * trueの場合、POSTを使用して接続します(初期値:false)。
    972         *
    973         * 通常はGETですが、外部から強制的に、POSTで送信したい場合に、
    974         * 設定します。
    975         * ただし、バイナリファイルをアップロードか、URLの長さ制限が、
    976         * {@value #MAX_GET_LENGTH} を超えた場合は、内部で自動的に、post にします。
    977         *
    978         * @og.rev 6.9.0.1 (2018/02/05) 新規作成
    979         *
    980         * @param       usePost true:POST使用/false:通常(GET)
    981         */
    982        public void usePost( final boolean usePost ) {
    983                isPost = usePost;
    984        }
    985
    986        /**
    987         * jsonによる2フェーズ認証を行う場合の設定。
    988         *
    989         * 認証用のデータをJSON形式の文字列で設定します。
    990         * urlは、認証するためのURLを指定します。
    991         *
    992         * @og.rev 8.0.0.0 (2021/08/31) 新規作成
    993         *
    994         * @param       json    認証用のデータを設定するJSON文字列
    995         * @param       url             JSON文字列で認証を行うURL(無ければnull)
    996         */
    997        public void setAuthJson( final String json,final String url ) {
    998                if( json != null && url != null ) {
    999                        authJson = json;
    1000                        authURL  = url;
    1001                }
    1002        // null 設定も可能とする。
    1003        //      else {
    1004        //              final String errMsg = "setAuthJson を使用する場合は、authJsonとauthURLの両方を設定してください。" + CR
    1005        //                                      + " authJson=[" + json + "]"    + CR
    1006        //                                      + " authURL =[" + url + "]" ;
    1007        //              throw new IllegalArgumentException( errMsg );
    1008        //      }
    1009        }
    1010
    1011        /**
    1012         * パラメータをJSONで指定する場合に使用します。
    1013         *
    1014         * JSON形式でパラメータを指定する場合に使用します。
    1015         * $XXXX$ 文字列は、先のjson認証で取得した各種ﾊﾟﾗﾒｰﾀを割り当てます。
    1016         *
    1017         * @og.rev 8.0.0.0 (2021/08/31) 新規作成
    1018         *
    1019         * @param       json    JSON文字列のパラメータ
    1020         */
    1021        public void setReqJson( final String json ) {
    1022                if( json == null ) { return; }
    1023
    1024                reqJson = json;
    1025
    1026                // $xxxxx$ 文字列を見つけて、Mapのｷｰとして登録しておく
    1027                int st = reqJson.indexOf( '$' );
    1028                while( st >= 0 ) {
    1029                        final int ed = reqJson.indexOf( '$',st+1 );
    1030                        if( ed > 0 ) {
    1031                                jsonMap.put( reqJson.substring( st+1,ed ) , "" );       // $ は含めず
    1032                        }
    1033                        st = reqJson.indexOf( '$',ed+1 );
    1034                }
    1035        }
    1036
    1037        /**
    1038         * trueの場合、POST時に強制的にﾘﾀﾞｲﾚｸﾄを行います(初期値:false)。
    1039         *
    1040         * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)
    1041         * @og.rev 8.0.0.0 (2021/07/31) httpclient5-5.1対応により LaxRedirectStrategy 廃止の為一旦削除
    1042         *
    1043         * @param       useRedirect     true:POST時に強制的にﾘﾀﾞｲﾚｸﾄ/false:通常
    1044         */
    1045        public void setPostRedirect( final boolean useRedirect ) {
    1046                postRedirect = useRedirect;
    1047        }
    1048
    1049        /**
    1050         * trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)。
    1051         *
    1052         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    1053         *
    1054         * @param       isDebug true:デバッグ用のメッセージを出力/false:通常
    1055         */
    1056        public void setDebug( final boolean isDebug ) {
    1057                this.isDebug = isDebug;
    1058        }
    1059
    1060        /**
    1061         * 実行結果のステータスコード 情報を取得します。
    1062         *
    1063         * 結果は、#readData() メソッドをコールしないと取れません。
    1064         * 未実行の場合は、-1 がセットされています。
    1065         *
    1066         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    1067         *
    1068         * @return      結果コード 情報
    1069         * @see         #readData()
    1070         */
    1071        public int getCode() { return rpsCode; }
    1072
    1073        /**
    1074         * メッセージ 情報を取得します。
    1075         *
    1076         * 結果は、#readData() メソッドをコールしないと取れません。
    1077         * 未実行の場合は、null がセットされています。
    1078         *
    1079         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    1080         *
    1081         * @return      メッセージ 情報
    1082         */
    1083        public String getMessage() { return rpsMessage; }
    1084
    1085        /**
    1086         * HttpURLConnection のレスポンスコードに対応するメッセージ文字列を返します。
    1087         *
    1088         * HttpURLConnection の getResponseCode() メソッドにより取得された、HTTPレスポンスコード
    1089         * に対応する文字列を返します。この文字列は、HttpURLConnection で定義された
    1090         * static 定数のコメントを、定義しています。
    1091         *
    1092         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    1093         *
    1094         * @param       code    HTTPレスポンスコード
    1095         *
    1096         * @return      レスポンスコードに対応する文字列
    1097         * @og.rtnNotNull
    1098         * @see HttpURLConnection#HTTP_ACCEPTED
    1099         */
    1100        public static String code2Message( final int code ) {
    1101                final String msg ;
    1102                switch( code ) {
    1103                        case 100                                                                                : msg = "100: 要求は続行可能です。"                                               ;       break;
    1104                        case 101                                                                                : msg = "101: プロトコルを切り替えます。"                            ;       break;
    1105                        case HttpURLConnection.HTTP_OK                                  : msg = "200: OK です。"                                                           ;       break;
    1106                        case HttpURLConnection.HTTP_CREATED                             : msg = "201: 作成されました。"                                                 ;       break;
    1107                        case HttpURLConnection.HTTP_ACCEPTED                    : msg = "202: 受け入れられました。"                                               ;       break;
    1108                        case HttpURLConnection.HTTP_NOT_AUTHORITATIVE   : msg = "203: 信頼できない情報です。"                                      ;       break;
    1109                        case HttpURLConnection.HTTP_NO_CONTENT                  : msg = "204: コンテンツがありません。"                                     ;       break;
    1110                        case HttpURLConnection.HTTP_RESET                               : msg = "205: コンテンツをリセットします。"                           ;       break;
    1111                        case HttpURLConnection.HTTP_PARTIAL                             : msg = "206: 部分的なコンテンツです。"                                     ;       break;
    1112                        case HttpURLConnection.HTTP_MULT_CHOICE                 : msg = "300: 複数の選択肢があります。"                                     ;       break;
    1113                        case HttpURLConnection.HTTP_MOVED_PERM                  : msg = "301: 永続的に移動されました。"                                     ;       break;
    1114                        case HttpURLConnection.HTTP_MOVED_TEMP                  : msg = "302: 一時的なリダイレクト。"                                      ;       break;
    1115                        case HttpURLConnection.HTTP_SEE_OTHER                   : msg = "303: ほかを参照してください。"                                     ;       break;
    1116                        case HttpURLConnection.HTTP_NOT_MODIFIED                : msg = "304: 変更されていません。"                                               ;       break;
    1117                        case HttpURLConnection.HTTP_USE_PROXY                   : msg = "305: プロキシを使用します。"                                      ;       break;
    1118                        case 306                                                                                : msg = "306: 仕様の拡張案です。"                                                ;       break;
    1119                        case 307                                                                                : msg = "307: 一時的なリダイレクトです。"                            ;       break;
    1120                        case HttpURLConnection.HTTP_BAD_REQUEST                 : msg = "400: 不当な要求です。"                                                 ;       break;
    1121                        case HttpURLConnection.HTTP_UNAUTHORIZED                : msg = "401: 認証されませんでした。"                                      ;       break;
    1122                        case HttpURLConnection.HTTP_PAYMENT_REQUIRED    : msg = "402: 支払いが必要です。"                                                ;       break;
    1123                        case HttpURLConnection.HTTP_FORBIDDEN                   : msg = "403: 禁止されています。"                                                ;       break;
    1124                        case HttpURLConnection.HTTP_NOT_FOUND                   : msg = "404: 見つかりませんでした。"                                      ;       break;
    1125                        case HttpURLConnection.HTTP_BAD_METHOD                  : msg = "405: メソッドは許可されません。"                            ;       break;
    1126                        case HttpURLConnection.HTTP_NOT_ACCEPTABLE              : msg = "406: 受け入れられません。"                                               ;       break;
    1127                        case HttpURLConnection.HTTP_PROXY_AUTH                  : msg = "407: プロキシの認証が必要です。"                            ;       break;
    1128                        case HttpURLConnection.HTTP_CLIENT_TIMEOUT              : msg = "408: 要求がタイムアウトしました。"                           ;       break;
    1129                        case HttpURLConnection.HTTP_CONFLICT                    : msg = "409: 重複しています。"                                                 ;       break;
    1130                        case HttpURLConnection.HTTP_GONE                                : msg = "410: 存在しません。"                                                  ;       break;
    1131                        case HttpURLConnection.HTTP_LENGTH_REQUIRED             : msg = "411: 長さが必要です。"                                                 ;       break;
    1132                        case HttpURLConnection.HTTP_PRECON_FAILED               : msg = "412: 前提条件が満たされていません。"                  ;       break;
    1133                        case HttpURLConnection.HTTP_ENTITY_TOO_LARGE    : msg = "413: 要求のエンティティが大きすぎます。"                ;       break;
    1134                        case HttpURLConnection.HTTP_REQ_TOO_LONG                : msg = "414: 要求のURIが大きすぎます。"                           ;       break;
    1135                        case HttpURLConnection.HTTP_UNSUPPORTED_TYPE    : msg = "415: サポートされないメディアタイプです。"               ;       break;
    1136                        case 416                                                                                : msg = "416: 要求された範囲は不十分です。"                           ;       break;
    1137                        case 417                                                                                : msg = "417: 要求どおりの処理が不可能です。"                  ;       break;
    1138                        case HttpURLConnection.HTTP_INTERNAL_ERROR              : msg = "500: 内部サーバエラーです。"                                      ;       break;
    1139                        case HttpURLConnection.HTTP_NOT_IMPLEMENTED             : msg = "501: 実装されていません。"                                               ;       break;
    1140                        case HttpURLConnection.HTTP_BAD_GATEWAY                 : msg = "502: 誤ったゲートウェイです。"                                     ;       break;
    1141                        case HttpURLConnection.HTTP_UNAVAILABLE                 : msg = "503: サービスが利用できません。"                            ;       break;
    1142                        case HttpURLConnection.HTTP_GATEWAY_TIMEOUT             : msg = "504: ゲートウェイがタイムアウトしました。"               ;       break;
    1143                        case HttpURLConnection.HTTP_VERSION                             : msg = "505: サポートされていないHTTPバージョンです。"   ;       break;
    1144                        default                                                                                 : msg = code + ": 未定義"                                                          ;       break;
    1145                }
    1146                return msg ;
    1147        }
    1148
    1149        /**
    1150         * サンプル実行用のメインメソッド
    1151         *
    1152         * <pre>
    1153         * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd]
    1154         *   args[A] : url                     ＵＲＬを指定します。GETの場合、パラメータは ?KEY=VALです
    1155         *   args[*] : [-param=key:value]      POST/GET時のﾊﾟﾗﾒｰﾀのｷｰと値を:で区切って指定します。(複数回指定可)
    1156         *   args[*] : [-header=key:value]     ﾍｯﾀﾞｰに設定するﾊﾟﾗﾒｰﾀのｷｰと値を:で区切って指定します。(複数回指定可)
    1157         *   args[*] : [-auth=user:pass]       BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します
    1158         *   args[*] : [-useForm=true/false]   認証方式にFORM認証を指定する場合、trueをｾｯﾄします(初期値:false) 8.0.0.0 (2021/08/20)
    1159         *   args[*] : [-proxy=host:port]      proxy を使用する場合のホストとポートを指定します。
    1160         *   args[*] : [-timeout=3]            接続タイムアウト時間を(秒)で指定します(初期値:無指定)
    1161         *   args[*] : [-encode=UTF-8]         エンコードを指定します。(初期値は UTF-8)
    1162         *   args[*] : [-out=ファイル名]       結果をファイルに出力します。初期値は標準出力です
    1163         *   args[*] : [-download=ファイル名]  ﾌｧｲﾙ名を指定して、ﾀﾞｳﾝﾛｰﾄﾞします
    1164         *   args[*] : [-upload=ファイル名]    ﾌｧｲﾙ名を指定して、multipart/form-dataでﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞします
    1165         *   args[*] : [-postRedirect=true]    POST時に強制的にﾘﾀﾞｲﾚｸﾄを行います(GET時は自動でﾘﾀﾞｲﾚｸﾄします)(初期値:false) 7.2.5.0 (2020/06/01)
    1166         *   args[*] : [-usePost=true]         POSTを強制的に使用する場合にｾｯﾄします(初期値:false) 8.0.0.0 (2021/08/20)
    1167         *   args[*] : [-errEx=true/false]     trueの場合、ﾚｽﾎﾟﾝｽｺｰﾄﾞが、4XX,5XX の時に RuntimeException を投げます(初期値:false)
    1168         *   args[*] : [#････]                 ｺﾒﾝﾄ引数。(BATﾌｧｲﾙ上に残しておきたいが、使用したくない場合など)
    1169         *   args[*] : [-debug=true/false]     trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)
    1170         * </pre>
    1171         *
    1172         * @og.rev 6.9.0.0 (2018/01/31) 新規作成
    1173         * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)引数を追加
    1174         *
    1175         * @param       args    コマンド引数配列
    1176         * @throws IOException 入出力エラーが発生したとき
    1177         */
    1178        public static void main( final String[] args ) throws IOException {
    1179                if( args.length < 2 ) {
    1180                        LogWriter.log( "Usage: java org.opengion.fukurou.util.HttpConnect [-data/-binary] … url"                                                                                                );
    1181                        LogWriter.log( "   args[A] : url                     URLを指定します｡GETの場合､ﾊﾟﾗﾒｰﾀは ?KEY=VALです"                                                                       );
    1182                        LogWriter.log( "   args[*] : [-param=key:value]      POST/GET時のﾊﾟﾗﾒｰﾀのｷｰと値を:で区切って指定します｡(複数回指定可)"                                        );
    1183                        LogWriter.log( "   args[*] : [-header=key:value]     ﾍｯﾀﾞｰに設定するﾊﾟﾗﾒｰﾀのｷｰと値を:で区切って指定します｡(複数回指定可)"                                );
    1184                        LogWriter.log( "   args[*] : [-auth=user:pass]       BASIC認証/FORM認証のｴﾘｱへのｱｸｾｽ時のﾕｰｻﾞｰとﾊﾟｽﾜｰﾄﾞを指定します"                                             );
    1185//                      LogWriter.log( "   args[*] : [-useForm=true/false]   認証方式にFORM認証を指定する場合､trueをｾｯﾄします(初期値:false)"                                 );
    1186                        LogWriter.log( "   args[*] : [-proxy=host:port]      proxy を使用する場合のﾎｽﾄとﾎﾟｰﾄを指定します｡"                                                                             );
    1187                        LogWriter.log( "   args[*] : [-timeout=3]            接続ﾀｲﾑｱｳﾄ時間を(秒)で指定します(初期値:無指定)"                                                                     );
    1188                        LogWriter.log( "   args[*] : [-encode=UTF-8]         ｴﾝｺｰﾄﾞを指定します｡(初期値は UTF-8)"                                                                                         );
    1189                        LogWriter.log( "   args[*] : [-out=ﾌｧｲﾙ名]           結果をﾌｧｲﾙに出力します｡初期値は標準出力です"                                                                           );
    1190                        LogWriter.log( "   args[*] : [-download=ﾌｧｲﾙ名]      ﾌｧｲﾙ名を指定して､ﾀﾞｳﾝﾛｰﾄﾞします"                                                                                                     );
    1191                        LogWriter.log( "   args[*] : [-upload=ﾌｧｲﾙ名]        ﾌｧｲﾙ名を指定して､multipart/form-dataでﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞします"                                                     );
    1192                        LogWriter.log( "   args[*] : [-postRedirect=true]    POST時に強制的にﾘﾀﾞｲﾚｸﾄを行います(GET時は自動でﾘﾀﾞｲﾚｸﾄします)(初期値:false)"             );
    1193                        LogWriter.log( "   args[*] : [-usePost=true]         POSTを強制的に使用する場合にｾｯﾄします(初期値:false)"                                                         );
    1194                        LogWriter.log( "   args[*] : [-errEx=true/false]     trueの場合､ﾚｽﾎﾟﾝｽｺｰﾄﾞが､4XX,5XX の時に RuntimeException を投げます(初期値:false)" );
    1195                        LogWriter.log( "   args[*] : [-authJson=JSONコード]  JSONコードで認証する場合に使用します。8.0.0.0 (2021/08/31)"                                            );
    1196                        LogWriter.log( "   args[*] : [-authURL=認証用URL]    JSONコードで認証するURLを指定します。8.0.0.0 (2021/08/31)"                                                   );
    1197                        LogWriter.log( "   args[*] : [#････]                 ｺﾒﾝﾄ引数｡(BATﾌｧｲﾙ上に残しておきたいが､使用したくない場合など)"                                            );
    1198                        LogWriter.log( "   args[*] : [-debug=true/false]     trueの場合､適度にﾃﾞﾊﾞｯｸﾞ用のﾒｯｾｰｼﾞを出力します(初期値:false)"                                               );
    1199                        return;
    1200                }
    1201
    1202                String  urlStr                  = null ;
    1203                final List<String> paramKey  = new ArrayList<>();                                               // ﾊﾟﾗﾒｰﾀｰｷｰ
    1204                final List<String> paramVal  = new ArrayList<>();                                               // ﾊﾟﾗﾒｰﾀｰ値
    1205                final List<String> headerKey = new ArrayList<>();                                               // ﾊﾟﾗﾒｰﾀｰｷｰ
    1206                final List<String> headerVal = new ArrayList<>();                                               // ﾊﾟﾗﾒｰﾀｰ値
    1207
    1208                String  userPass                = null ;                                        // -auth
    1209//              boolean useForm                 = false ;                                       // -useForm                     // 8.0.0.0 (2021/08/20)
    1210                String  proxy                   = null ;                                        // -proxy
    1211                int             timeout                 = -1 ;                                          // -timeout
    1212                String  encode                  = DEFAULT_CHARSET ;                     // -encode
    1213                String  outFile                 = null ;                                        // -out
    1214                String  dwldFile                = null ;                                        // -download
    1215                String  upldFile                = null ;                                        // -upload
    1216                boolean isEx                    = false ;                                       // -errEx
    1217                boolean isDebug                 = false ;                                       // -debug
    1218                boolean postRedirect    = false ;                                       // -postRedirect        // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)
    1219                boolean nonWriter               = false ;                                       // -out 指定で見つからない場合
    1220                boolean isPost                  = false ;                                       // -usePost
    1221                String  authJson                = null ;                                        // -authJson            // 8.0.0.0 (2021/08/31)
    1222                String  authURL                 = null ;                                        // -authURL                     // 8.0.0.0 (2021/08/31)
    1223                String  reqJson                 = null ;                                        // -reqJson                     // 8.0.0.0 (2021/08/31)
    1224
    1225//              int             code                    = -1;
    1226
    1227                for( final String arg : args ) {
    1228                        if( arg.startsWith( "-param=" ) ) {
    1229                                final String[] prm = StringUtil.csv2Array( arg.substring( "-param=".length() ) , '=' , 2 );
    1230                                paramKey.add( prm[0] );
    1231                                paramVal.add( prm[1] );
    1232                        }
    1233                        else if( arg.startsWith( "-header=" ) ) {
    1234                                final String[] prm = StringUtil.csv2Array( arg.substring( "-header=".length() ) , '=' , 2 );
    1235                                headerKey.add( prm[0] );
    1236                                headerVal.add( prm[1] );
    1237                        }
    1238                        else if( arg.startsWith( "-auth=" ) ) {
    1239                                userPass = arg.substring( "-auth=".length() );
    1240                                if( StringUtil.isNull( userPass ) ) {
    1241                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1242                                }
    1243                        }
    1244//                      else if( arg.startsWith( "-useForm=" ) ) {
    1245//                              useForm = "true".equalsIgnoreCase( arg.substring( "-useForm=".length() ) );
    1246//                      }
    1247                        else if( arg.startsWith( "-proxy=" ) ) {
    1248                                proxy = arg.substring( "-proxy=".length() );
    1249                                if( StringUtil.isNull( proxy ) ) {
    1250                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1251                                }
    1252                        }
    1253                        else if( arg.startsWith( "-timeout=" ) ) {
    1254                                timeout = Integer.parseInt( arg.substring( "-timeout=".length() ) );
    1255                        }
    1256                        else if( arg.startsWith( "-encode=" ) ) {
    1257                                encode = arg.substring( "-encode=".length() );
    1258                                if( StringUtil.isNull( encode ) ) {
    1259                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1260                                }
    1261                        }
    1262                        else if( arg.startsWith( "-out=" ) ) {
    1263                                outFile = arg.substring( "-out=".length() );
    1264                                if( StringUtil.isNull( outFile ) ) {
    1265                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1266                                }
    1267                                else {
    1268                                        if( "null".equalsIgnoreCase( outFile ) || "none".equalsIgnoreCase( outFile ) ) {
    1269                                                outFile   = null;
    1270                                                nonWriter = true;
    1271                                        }
    1272                                }
    1273                        }
    1274                        else if( arg.startsWith( "-download=" ) ) {
    1275                                dwldFile = arg.substring( "-download=".length() );
    1276                                if( StringUtil.isNull( dwldFile ) ) {
    1277                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1278                                }
    1279                        }
    1280                        else if( arg.startsWith( "-upload=" ) ) {
    1281                                upldFile = arg.substring( "-upload=".length() );
    1282                                if( StringUtil.isNull( upldFile ) ) {
    1283                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1284                                }
    1285                        }
    1286                        else if( arg.startsWith( "-errEx=" ) ) {
    1287                                isEx = "true".equalsIgnoreCase( arg.substring( "-errEx=".length() ) );
    1288                        }
    1289                        // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にﾘﾀﾞｲﾚｸﾄ)
    1290                        else if( arg.startsWith( "-postRedirect=" ) ) {
    1291                                postRedirect = "true".equalsIgnoreCase( arg.substring( "-postRedirect=".length() ) );
    1292                        }
    1293                        else if( arg.startsWith( "-debug=" ) ) {
    1294                                isDebug = "true".equalsIgnoreCase( arg.substring( "-debug=".length() ) );
    1295                        }
    1296                        else if( arg.startsWith( "-usePost=" ) ) {
    1297                                isPost = "true".equalsIgnoreCase( arg.substring( "-usePost=".length() ) );
    1298                        }
    1299                        else if( arg.startsWith( "-authJson=" ) ) {                             // 8.0.0.0 (2021/08/31)
    1300                                authJson = arg.substring( "-authJson=".length() );
    1301                                if( StringUtil.isNull( authJson ) ) {
    1302                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1303                                }
    1304                        }
    1305                        else if( arg.startsWith( "-authURL=" ) ) {                              // 8.0.0.0 (2021/08/31)
    1306                                authURL = arg.substring( "-authURL=".length() );
    1307                                if( StringUtil.isNull( authURL ) ) {
    1308                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1309                                }
    1310                        }
    1311                        else if( arg.startsWith( "-reqJson=" ) ) {                              // 8.0.0.0 (2021/08/31)
    1312                                reqJson = arg.substring( "-reqJson=".length() );
    1313                                if( StringUtil.isNull( reqJson ) ) {
    1314                                        System.err.println( arg + "指定した場合は、引数を設定してください。" );
    1315                                }
    1316                        }
    1317                        else if( StringUtil.startsChar( arg , '-' ) ) {                 // 引数が未定義(処理は継続させます。)
    1318                                System.err.println( "Error Argment:" + arg );
    1319                        }
    1320                        else if( StringUtil.startsChar( arg , '#' ) ) {                 // 引数がコメント
    1321                                continue;
    1322                        }
    1323                        else {
    1324                                urlStr = arg;
    1325                        }
    1326                }
    1327
    1328                try {                                                                   // try catch を入れます。
    1329                        final HttpConnect conn = new HttpConnect( urlStr,userPass );
    1330                        conn.usePost( isPost );
    1331                        conn.setDebug( isDebug );                       // 最初に入れておけば、それ以降、有効になります。
    1332
    1333                        for( int i=0; i<paramKey.size(); i++ ) {
    1334                                conn.addRequestProperty( paramKey.get(i) , paramVal.get(i) );
    1335                        }
    1336
    1337                        for( int i=0; i<headerKey.size(); i++ ) {
    1338                                conn.addHeaderProperty( headerKey.get(i) , headerVal.get(i) );
    1339                        }
    1340
    1341                        // 6.8.1.3 (2017/08/04) proxy の設定
    1342                        if( !StringUtil.isNull( proxy ) ) {
    1343                                final String[] prm = StringUtil.csv2Array( proxy , ':' , 2 );
    1344                                final String host = prm[0];
    1345                                final int    port = Integer.parseInt( prm[1] );
    1346                                conn.setProxy( host , port );
    1347                        }
    1348
    1349                        conn.setCharset(                encode );                               // encode 指定
    1350                        conn.setTimeout(                timeout );                              // timeout属性追加
    1351                        conn.setUploadFile(             upldFile );
    1352                        conn.setDownloadFile(   dwldFile );
    1353                        conn.setPostRedirect(   postRedirect );                 // 7.2.5.0 (2020/06/01)
    1354                        conn.setAuthJson(               authJson,authURL );             // 8.0.0.0 (2021/08/31)
    1355                        conn.setReqJson(                reqJson );                              // 8.0.0.0 (2021/08/31)
    1356
    1357                        final String outData = conn.readData();                 // 8.0.0.0 (2021/08/20) ﾃｽﾄ用
    1358
    1359                        try( PrintWriter writer = StringUtil.isNull( outFile )
    1360                                                                                                ? FileUtil.getLogWriter( "System.out" )
    1361                                                                                                : FileUtil.getPrintWriter( new File( outFile ),encode ) ) {
    1362                                if( !nonWriter ) {
    1363                                        writer.println( outData );
    1364                                }
    1365                                final int code = conn.getCode();
    1366
    1367                                // isEx=trueの場合、ﾚｽﾎﾟﾝｽｺｰﾄﾞが、4XX,5XX の時に RuntimeException を投げます
    1368                                if( code >= 400 ) {
    1369                                        final String errMsg = conn.getMessage();
    1370                                        writer.println( errMsg );
    1371                                        if( isEx ) {
    1372                                                throw new OgRuntimeException( errMsg );
    1373                                        }
    1374                                        else {
    1375                                                System.exit( code );
    1376                                        }
    1377                                }
    1378                        }
    1379                }
    1380                catch( final Throwable th ) {
    1381        //              throw new OgRuntimeException( th );
    1382                        System.err.println( th.getMessage() );
    1383                }
    1384        }
    1385}